Merge pull request #56483 from vnen/gdscript-warning-annotation

Add annotation to ignore warnings
This commit is contained in:
Rémi Verschelde 2022-01-05 09:05:56 +01:00 committed by GitHub
commit 6d4ed65f4c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 117 additions and 29 deletions

View file

@ -39,6 +39,7 @@
#ifdef DEBUG_ENABLED
#include "core/os/os.h"
#include "core/string/string_builder.h"
#include "gdscript_warning.h"
#endif // DEBUG_ENABLED
#ifdef TOOLS_ENABLED
@ -132,9 +133,9 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@export_flags_3d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_RENDER, Variant::INT>);
register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>);
register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>);
register_annotation(MethodInfo("@warning_ignore", { Variant::STRING, "warning" }), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, 0, true);
// Networking.
register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, 4, true);
// TODO: Warning annotations.
}
GDScriptParser::~GDScriptParser() {
@ -196,6 +197,10 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_
return;
}
if (ignored_warning_codes.has(p_code)) {
return;
}
String warn_name = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)p_code).to_lower();
if (ignored_warnings.has(warn_name)) {
return;
@ -701,24 +706,21 @@ void GDScriptParser::parse_extends() {
template <class T>
void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(), AnnotationInfo::TargetKind p_target, const String &p_member_kind) {
advance();
T *member = (this->*p_parse_function)();
if (member == nullptr) {
return;
}
#ifdef TOOLS_ENABLED
int doc_comment_line = member->start_line - 1;
int doc_comment_line = previous.start_line - 1;
#endif // TOOLS_ENABLED
// Consume annotations.
List<AnnotationNode *> annotations;
while (!annotation_stack.is_empty()) {
AnnotationNode *last_annotation = annotation_stack.back()->get();
if (last_annotation->applies_to(p_target)) {
member->annotations.push_front(last_annotation);
annotations.push_front(last_annotation);
annotation_stack.pop_back();
} else {
push_error(vformat(R"(Annotation "%s" cannot be applied to a %s.)", last_annotation->name, p_member_kind));
clear_unused_annotations();
return;
}
#ifdef TOOLS_ENABLED
if (last_annotation->start_line == doc_comment_line) {
@ -727,6 +729,16 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
#endif // TOOLS_ENABLED
}
T *member = (this->*p_parse_function)();
if (member == nullptr) {
return;
}
// Apply annotations.
for (AnnotationNode *&annotation : annotations) {
member->annotations.push_back(annotation);
}
#ifdef TOOLS_ENABLED
// Consume doc comments.
class_doc_line = MIN(class_doc_line, doc_comment_line - 1);
@ -1507,6 +1519,8 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
bool unreachable = current_suite->has_return && !current_suite->has_unreachable_code;
#endif
bool is_annotation = false;
switch (current.type) {
case GDScriptTokenizer::Token::PASS:
advance();
@ -1576,6 +1590,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
break;
case GDScriptTokenizer::Token::ANNOTATION: {
advance();
is_annotation = true;
AnnotationNode *annotation = parse_annotation(AnnotationInfo::STATEMENT);
if (annotation != nullptr) {
annotation_stack.push_back(annotation);
@ -1616,6 +1631,18 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
}
}
// Apply annotations to statement.
while (!is_annotation && result != nullptr && !annotation_stack.is_empty()) {
AnnotationNode *last_annotation = annotation_stack.back()->get();
if (last_annotation->applies_to(AnnotationInfo::STATEMENT)) {
result->annotations.push_front(last_annotation);
annotation_stack.pop_back();
} else {
push_error(vformat(R"(Annotation "%s" cannot be applied to a statement.)", last_annotation->name));
clear_unused_annotations();
}
}
#ifdef DEBUG_ENABLED
if (unreachable && result != nullptr) {
current_suite->has_unreachable_code = true;
@ -3552,7 +3579,24 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
}
bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Node *p_node) {
ERR_FAIL_V_MSG(false, "Not implemented.");
#ifdef DEBUG_ENABLED
bool has_error = false;
for (const Variant &warning_name : p_annotation->resolved_arguments) {
GDScriptWarning::Code warning = GDScriptWarning::get_code_from_name(String(warning_name).to_upper());
if (warning == GDScriptWarning::WARNING_MAX) {
push_error(vformat(R"(Invalid warning name: "%s".)", warning_name), p_annotation);
has_error = true;
} else {
p_node->ignored_warnings.push_back(warning);
}
}
return !has_error;
#else // ! DEBUG_ENABLED
// Only available in debug builds.
return true;
#endif // DEBUG_ENABLED
}
template <Multiplayer::RPCMode t_mode>