diff options
Diffstat (limited to 'modules/gdscript/gdscript_editor.cpp')
-rw-r--r-- | modules/gdscript/gdscript_editor.cpp | 203 |
1 files changed, 125 insertions, 78 deletions
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index cd34feb8b3..d27ea974e3 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -143,14 +143,26 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li #endif if (err) { if (r_errors) { - for (const GDScriptParser::ParserError &E : parser.get_errors()) { - const GDScriptParser::ParserError &pe = E; + for (const GDScriptParser::ParserError &pe : parser.get_errors()) { ScriptLanguage::ScriptError e; + e.path = p_path; e.line = pe.line; e.column = pe.column; e.message = pe.message; r_errors->push_back(e); } + + for (KeyValue<String, Ref<GDScriptParserRef>> E : analyzer.get_depended_parsers()) { + GDScriptParser *depended_parser = E.value->get_parser(); + for (const GDScriptParser::ParserError &pe : depended_parser->get_errors()) { + ScriptLanguage::ScriptError e; + e.path = E.key; + e.line = pe.line; + e.column = pe.column; + e.message = pe.message; + r_errors->push_back(e); + } + } } return false; } else { @@ -221,6 +233,10 @@ Script *GDScriptLanguage::create_script() const { /* DEBUGGER FUNCTIONS */ +thread_local int GDScriptLanguage::_debug_parse_err_line = -1; +thread_local String GDScriptLanguage::_debug_parse_err_file; +thread_local String GDScriptLanguage::_debug_error; + bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) { // break because of parse error @@ -229,6 +245,9 @@ bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const _debug_parse_err_file = p_file; _debug_error = p_error; EngineDebugger::get_script_debugger()->debug(this, false, true); + // Because this is thread local, clear the memory afterwards. + _debug_parse_err_file = String(); + _debug_error = String(); return true; } else { return false; @@ -236,12 +255,15 @@ bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const } bool GDScriptLanguage::debug_break(const String &p_error, bool p_allow_continue) { - if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) { + if (EngineDebugger::is_active()) { _debug_parse_err_line = -1; _debug_parse_err_file = ""; _debug_error = p_error; bool is_error_breakpoint = p_error != "Breakpoint"; EngineDebugger::get_script_debugger()->debug(this, p_allow_continue, is_error_breakpoint); + // Because this is thread local, clear the memory afterwards. + _debug_parse_err_file = String(); + _debug_error = String(); return true; } else { return false; @@ -257,7 +279,7 @@ int GDScriptLanguage::debug_get_stack_level_count() const { return 1; } - return _debug_call_stack_pos; + return _call_stack.stack_pos; } int GDScriptLanguage::debug_get_stack_level_line(int p_level) const { @@ -265,11 +287,11 @@ int GDScriptLanguage::debug_get_stack_level_line(int p_level) const { return _debug_parse_err_line; } - ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, -1); + ERR_FAIL_INDEX_V(p_level, _call_stack.stack_pos, -1); - int l = _debug_call_stack_pos - p_level - 1; + int l = _call_stack.stack_pos - p_level - 1; - return *(_call_stack[l].line); + return *(_call_stack.levels[l].line); } String GDScriptLanguage::debug_get_stack_level_function(int p_level) const { @@ -277,9 +299,9 @@ String GDScriptLanguage::debug_get_stack_level_function(int p_level) const { return ""; } - ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, ""); - int l = _debug_call_stack_pos - p_level - 1; - return _call_stack[l].function->get_name(); + ERR_FAIL_INDEX_V(p_level, _call_stack.stack_pos, ""); + int l = _call_stack.stack_pos - p_level - 1; + return _call_stack.levels[l].function->get_name(); } String GDScriptLanguage::debug_get_stack_level_source(int p_level) const { @@ -287,9 +309,9 @@ String GDScriptLanguage::debug_get_stack_level_source(int p_level) const { return _debug_parse_err_file; } - ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, ""); - int l = _debug_call_stack_pos - p_level - 1; - return _call_stack[l].function->get_source(); + ERR_FAIL_INDEX_V(p_level, _call_stack.stack_pos, ""); + int l = _call_stack.stack_pos - p_level - 1; + return _call_stack.levels[l].function->get_source(); } void GDScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { @@ -297,17 +319,17 @@ void GDScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p return; } - ERR_FAIL_INDEX(p_level, _debug_call_stack_pos); - int l = _debug_call_stack_pos - p_level - 1; + ERR_FAIL_INDEX(p_level, _call_stack.stack_pos); + int l = _call_stack.stack_pos - p_level - 1; - GDScriptFunction *f = _call_stack[l].function; + GDScriptFunction *f = _call_stack.levels[l].function; List<Pair<StringName, int>> locals; - f->debug_get_stack_member_state(*_call_stack[l].line, &locals); + f->debug_get_stack_member_state(*_call_stack.levels[l].line, &locals); for (const Pair<StringName, int> &E : locals) { p_locals->push_back(E.first); - p_values->push_back(_call_stack[l].stack[E.second]); + p_values->push_back(_call_stack.levels[l].stack[E.second]); } } @@ -316,10 +338,10 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> * return; } - ERR_FAIL_INDEX(p_level, _debug_call_stack_pos); - int l = _debug_call_stack_pos - p_level - 1; + ERR_FAIL_INDEX(p_level, _call_stack.stack_pos); + int l = _call_stack.stack_pos - p_level - 1; - GDScriptInstance *instance = _call_stack[l].instance; + GDScriptInstance *instance = _call_stack.levels[l].instance; if (!instance) { return; @@ -341,10 +363,10 @@ ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) { return nullptr; } - ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, nullptr); + ERR_FAIL_INDEX_V(p_level, _call_stack.stack_pos, nullptr); - int l = _debug_call_stack_pos - p_level - 1; - ScriptInstance *instance = _call_stack[l].instance; + int l = _call_stack.stack_pos - p_level - 1; + ScriptInstance *instance = _call_stack.levels[l].instance; return instance; } @@ -796,9 +818,10 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a ScriptLanguage::CodeCompletionOption node("Node", ScriptLanguage::CODE_COMPLETION_KIND_CLASS); node.insert_text = node.display.quote(p_quote_style); r_result.insert(node.display, node); - List<StringName> node_types; - ClassDB::get_inheriters_from_class("Node", &node_types); - for (const StringName &E : node_types) { + + List<StringName> native_classes; + ClassDB::get_inheriters_from_class("Node", &native_classes); + for (const StringName &E : native_classes) { if (!ClassDB::is_class_exposed(E)) { continue; } @@ -806,6 +829,17 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a option.insert_text = option.display.quote(p_quote_style); r_result.insert(option.display, option); } + + List<StringName> global_script_classes; + ScriptServer::get_global_class_list(&global_script_classes); + for (const StringName &E : global_script_classes) { + if (!ClassDB::is_parent_class(ScriptServer::get_global_class_native_base(E), "Node")) { + continue; + } + ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS); + option.insert_text = option.display.quote(p_quote_style); + r_result.insert(option.display, option); + } } else if (p_annotation->name == SNAME("@warning_ignore")) { for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) { ScriptLanguage::CodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); @@ -1381,7 +1415,7 @@ struct RecursionCheck { } }; -static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); +static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::IdentifierNode *p_identifier, GDScriptCompletionIdentifier &r_type); static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type); static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, GDScriptCompletionIdentifier &r_type); @@ -1435,17 +1469,17 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, } break; case GDScriptParser::Node::SELF: { if (p_context.current_class) { - r_type.type.kind = GDScriptParser::DataType::CLASS; - r_type.type.type_source = GDScriptParser::DataType::INFERRED; - r_type.type.is_constant = true; - r_type.type.class_type = p_context.current_class; - r_type.value = p_context.base; + if (p_context.type != GDScriptParser::COMPLETION_SUPER_METHOD) { + r_type.type = p_context.current_class->get_datatype(); + } else { + r_type.type = p_context.current_class->base_type; + } found = true; } } break; case GDScriptParser::Node::IDENTIFIER: { const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(p_expression); - found = _guess_identifier_type(p_context, id->name, r_type); + found = _guess_identifier_type(p_context, id, r_type); } break; case GDScriptParser::Node::DICTIONARY: { // Try to recreate the dictionary. @@ -1888,7 +1922,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, return found; } -static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, const StringName &p_identifier, GDScriptCompletionIdentifier &r_type) { +static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::IdentifierNode *p_identifier, GDScriptCompletionIdentifier &r_type) { static int recursion_depth = 0; RecursionCheck recursion(&recursion_depth); if (unlikely(recursion.check())) { @@ -1902,36 +1936,49 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, GDScriptParser::SuiteNode *suite = p_context.current_suite; bool is_function_parameter = false; - if (suite) { - if (suite->has_local(p_identifier)) { - const GDScriptParser::SuiteNode::Local &local = suite->get_local(p_identifier); + bool can_be_local = true; + switch (p_identifier->source) { + case GDScriptParser::IdentifierNode::MEMBER_VARIABLE: + case GDScriptParser::IdentifierNode::MEMBER_CONSTANT: + case GDScriptParser::IdentifierNode::MEMBER_FUNCTION: + case GDScriptParser::IdentifierNode::MEMBER_SIGNAL: + case GDScriptParser::IdentifierNode::MEMBER_CLASS: + case GDScriptParser::IdentifierNode::INHERITED_VARIABLE: + case GDScriptParser::IdentifierNode::STATIC_VARIABLE: + can_be_local = false; + break; + default: + break; + } - id_type = local.get_datatype(); + if (can_be_local && suite && suite->has_local(p_identifier->name)) { + const GDScriptParser::SuiteNode::Local &local = suite->get_local(p_identifier->name); - // Check initializer as the first assignment. - switch (local.type) { - case GDScriptParser::SuiteNode::Local::VARIABLE: - if (local.variable->initializer) { - last_assign_line = local.variable->initializer->end_line; - last_assigned_expression = local.variable->initializer; - } - break; - case GDScriptParser::SuiteNode::Local::CONSTANT: - if (local.constant->initializer) { - last_assign_line = local.constant->initializer->end_line; - last_assigned_expression = local.constant->initializer; - } - break; - case GDScriptParser::SuiteNode::Local::PARAMETER: - if (local.parameter->initializer) { - last_assign_line = local.parameter->initializer->end_line; - last_assigned_expression = local.parameter->initializer; - } - is_function_parameter = true; - break; - default: - break; - } + id_type = local.get_datatype(); + + // Check initializer as the first assignment. + switch (local.type) { + case GDScriptParser::SuiteNode::Local::VARIABLE: + if (local.variable->initializer) { + last_assign_line = local.variable->initializer->end_line; + last_assigned_expression = local.variable->initializer; + } + break; + case GDScriptParser::SuiteNode::Local::CONSTANT: + if (local.constant->initializer) { + last_assign_line = local.constant->initializer->end_line; + last_assigned_expression = local.constant->initializer; + } + break; + case GDScriptParser::SuiteNode::Local::PARAMETER: + if (local.parameter->initializer) { + last_assign_line = local.parameter->initializer->end_line; + last_assigned_expression = local.parameter->initializer; + } + is_function_parameter = true; + break; + default: + break; } } @@ -1946,7 +1993,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::AssignmentNode *assign = static_cast<const GDScriptParser::AssignmentNode *>(suite->statements[i]); if (assign->end_line > last_assign_line && assign->assignee && assign->assigned_value && assign->assignee->type == GDScriptParser::Node::IDENTIFIER) { const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(assign->assignee); - if (id->name == p_identifier) { + if (id->name == p_identifier->name && id->source == p_identifier->source) { last_assign_line = assign->assigned_value->end_line; last_assigned_expression = assign->assigned_value; } @@ -1964,7 +2011,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, // Credit: Zylann. // TODO: this could be hacked to detect ANDed conditions too... const GDScriptParser::TypeTestNode *type_test = static_cast<const GDScriptParser::TypeTestNode *>(suite->parent_if->condition); - if (type_test->operand && type_test->test_type && type_test->operand->type == GDScriptParser::Node::IDENTIFIER && static_cast<const GDScriptParser::IdentifierNode *>(type_test->operand)->name == p_identifier) { + if (type_test->operand && type_test->test_type && type_test->operand->type == GDScriptParser::Node::IDENTIFIER && static_cast<const GDScriptParser::IdentifierNode *>(type_test->operand)->name == p_identifier->name && static_cast<const GDScriptParser::IdentifierNode *>(type_test->operand)->source == p_identifier->source) { // Bingo. GDScriptParser::CompletionContext c = p_context; c.current_line = type_test->operand->start_line; @@ -2000,8 +2047,8 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, case GDScriptParser::DataType::CLASS: if (base_type.class_type->has_function(p_context.current_function->identifier->name)) { GDScriptParser::FunctionNode *parent_function = base_type.class_type->get_member(p_context.current_function->identifier->name).function; - if (parent_function->parameters_indices.has(p_identifier)) { - const GDScriptParser::ParameterNode *parameter = parent_function->parameters[parent_function->parameters_indices[p_identifier]]; + if (parent_function->parameters_indices.has(p_identifier->name)) { + const GDScriptParser::ParameterNode *parameter = parent_function->parameters[parent_function->parameters_indices[p_identifier->name]]; if ((!id_type.is_set() || id_type.is_variant()) && parameter->get_datatype().is_hard_type()) { id_type = parameter->get_datatype(); } @@ -2026,7 +2073,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, MethodInfo info; if (ClassDB::get_method_info(base_type.native_type, p_context.current_function->identifier->name, &info)) { for (const PropertyInfo &E : info.arguments) { - if (E.name == p_identifier) { + if (E.name == p_identifier->name) { r_type = _type_from_property(E); return true; } @@ -2054,14 +2101,14 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, base.type.class_type = p_context.current_class; base.type.is_meta_type = p_context.current_function && p_context.current_function->is_static; - if (_guess_identifier_type_from_base(p_context, base, p_identifier, r_type)) { + if (_guess_identifier_type_from_base(p_context, base, p_identifier->name, r_type)) { return true; } } // Check global scripts. - if (ScriptServer::is_global_class(p_identifier)) { - String script = ScriptServer::get_global_class_path(p_identifier); + if (ScriptServer::is_global_class(p_identifier->name)) { + String script = ScriptServer::get_global_class_path(p_identifier->name); if (script.to_lower().ends_with(".gd")) { Error err = OK; Ref<GDScriptParserRef> parser = GDScriptCache::get_parser(script, GDScriptParserRef::INTERFACE_SOLVED, err); @@ -2077,7 +2124,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, return true; } } else { - Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(p_identifier)); + Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(p_identifier->name)); if (scr.is_valid()) { r_type = _type_from_variant(scr); r_type.type.is_meta_type = true; @@ -2088,20 +2135,20 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context, } // Check global variables (including autoloads). - if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(p_identifier)) { - r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[p_identifier]); + if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(p_identifier->name)) { + r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[p_identifier->name]); return true; } // Check ClassDB. - if (ClassDB::class_exists(p_identifier) && ClassDB::is_class_exposed(p_identifier)) { + if (ClassDB::class_exists(p_identifier->name) && ClassDB::is_class_exposed(p_identifier->name)) { r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; r_type.type.kind = GDScriptParser::DataType::NATIVE; - r_type.type.native_type = p_identifier; + r_type.type.native_type = p_identifier->name; r_type.type.is_constant = true; - if (Engine::get_singleton()->has_singleton(p_identifier)) { + if (Engine::get_singleton()->has_singleton(p_identifier->name)) { r_type.type.is_meta_type = false; - r_type.value = Engine::get_singleton()->get_singleton_object(p_identifier); + r_type.value = Engine::get_singleton()->get_singleton_object(p_identifier->name); } else { r_type.type.is_meta_type = true; r_type.value = Variant(); |