summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/gdscript_editor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gdscript_editor.cpp')
-rw-r--r--modules/gdscript/gdscript_editor.cpp203
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();