diff options
Diffstat (limited to 'modules/gdscript/gdscript_parser.cpp')
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 62 |
1 files changed, 53 insertions, 9 deletions
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index d12795d320..2faf0febca 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -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> |