diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 02f001edc9c..d240b6ef486 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -430,6 +430,12 @@
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an identifier contains characters that can be confused with something else, like when mixing different alphabets.
+
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an identifier declared in the nested block has the same name as an identifier declared below in the parent block.
+
+
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an identifier that will be shadowed below in the block is used.
+
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a constant is used as a function.
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 01e94ebb224..cb049136201 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -1772,6 +1772,15 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi
bool is_constant = p_assignable->type == GDScriptParser::Node::CONSTANT;
+#ifdef DEBUG_ENABLED
+ if (p_assignable->identifier != nullptr && p_assignable->identifier->suite != nullptr && p_assignable->identifier->suite->parent_block != nullptr) {
+ if (p_assignable->identifier->suite->parent_block->has_local(p_assignable->identifier->name)) {
+ const GDScriptParser::SuiteNode::Local &local = p_assignable->identifier->suite->parent_block->get_local(p_assignable->identifier->name);
+ parser->push_warning(p_assignable->identifier, GDScriptWarning::CONFUSABLE_LOCAL_DECLARATION, local.get_name(), p_assignable->identifier->name);
+ }
+ }
+#endif
+
GDScriptParser::DataType specified_type;
bool has_specified_type = p_assignable->datatype_specifier != nullptr;
if (has_specified_type) {
@@ -3518,12 +3527,14 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
case GDScriptParser::ClassNode::Member::FUNCTION: {
if (is_base && (!base.is_meta_type || member.function->is_static)) {
p_identifier->set_datatype(make_callable_type(member.function->info));
+ p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_FUNCTION;
return;
}
} break;
case GDScriptParser::ClassNode::Member::CLASS: {
reduce_identifier_from_base_set_class(p_identifier, member.get_datatype());
+ p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CLASS;
return;
}
@@ -3662,9 +3673,17 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
found_source = true;
} break;
case GDScriptParser::IdentifierNode::UNDEFINED_SOURCE:
+ case GDScriptParser::IdentifierNode::MEMBER_FUNCTION:
+ case GDScriptParser::IdentifierNode::MEMBER_CLASS:
break;
}
+#ifdef DEBUG_ENABLED
+ if (!found_source && p_identifier->suite != nullptr && p_identifier->suite->has_local(p_identifier->name)) {
+ parser->push_warning(p_identifier, GDScriptWarning::CONFUSABLE_LOCAL_USAGE, p_identifier->name);
+ }
+#endif
+
// Not a local, so check members.
if (!found_source) {
reduce_identifier_from_base(p_identifier);
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 745ccbb1ed9..2a52db4158c 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -225,194 +225,211 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
StringName identifier = in->name;
- // Try function parameters.
- if (codegen.parameters.has(identifier)) {
- return codegen.parameters[identifier];
- }
-
- // Try local variables and constants.
- if (!p_initializer && codegen.locals.has(identifier)) {
- return codegen.locals[identifier];
- }
-
- // Try class members.
- if (_is_class_member_property(codegen, identifier)) {
- // Get property.
- GDScriptCodeGenerator::Address temp = codegen.add_temporary(_gdtype_from_datatype(p_expression->get_datatype(), codegen.script));
- gen->write_get_member(temp, identifier);
- return temp;
- }
-
- // Try members.
- if (!codegen.function_node || !codegen.function_node->is_static) {
- // Try member variables.
- if (codegen.script->member_indices.has(identifier)) {
- if (codegen.script->member_indices[identifier].getter != StringName() && codegen.script->member_indices[identifier].getter != codegen.function_name) {
- // Perform getter.
- GDScriptCodeGenerator::Address temp = codegen.add_temporary(codegen.script->member_indices[identifier].data_type);
- Vector args; // No argument needed.
- gen->write_call_self(temp, codegen.script->member_indices[identifier].getter, args);
- return temp;
- } else {
- // No getter or inside getter: direct member access.
- int idx = codegen.script->member_indices[identifier].index;
- return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::MEMBER, idx, codegen.script->get_member_type(identifier));
+ switch (in->source) {
+ // LOCALS.
+ case GDScriptParser::IdentifierNode::FUNCTION_PARAMETER:
+ case GDScriptParser::IdentifierNode::LOCAL_VARIABLE:
+ case GDScriptParser::IdentifierNode::LOCAL_CONSTANT:
+ case GDScriptParser::IdentifierNode::LOCAL_ITERATOR:
+ case GDScriptParser::IdentifierNode::LOCAL_BIND: {
+ // Try function parameters.
+ if (codegen.parameters.has(identifier)) {
+ return codegen.parameters[identifier];
}
- }
- }
- // Try static variables.
- {
- GDScript *scr = codegen.script;
- while (scr) {
- if (scr->static_variables_indices.has(identifier)) {
- if (scr->static_variables_indices[identifier].getter != StringName() && scr->static_variables_indices[identifier].getter != codegen.function_name) {
- // Perform getter.
- GDScriptCodeGenerator::Address temp = codegen.add_temporary(scr->static_variables_indices[identifier].data_type);
- GDScriptCodeGenerator::Address class_addr(GDScriptCodeGenerator::Address::CLASS);
- Vector args; // No argument needed.
- gen->write_call(temp, class_addr, scr->static_variables_indices[identifier].getter, args);
- return temp;
- } else {
- // No getter or inside getter: direct variable access.
- GDScriptCodeGenerator::Address temp = codegen.add_temporary(scr->static_variables_indices[identifier].data_type);
- GDScriptCodeGenerator::Address _class = codegen.add_constant(scr);
- int index = scr->static_variables_indices[identifier].index;
- gen->write_get_static_variable(temp, _class, index);
- return temp;
+ // Try local variables and constants.
+ if (!p_initializer && codegen.locals.has(identifier)) {
+ return codegen.locals[identifier];
+ }
+ } break;
+
+ // MEMBERS.
+ case GDScriptParser::IdentifierNode::MEMBER_VARIABLE:
+ case GDScriptParser::IdentifierNode::INHERITED_VARIABLE: {
+ // Try class members.
+ if (_is_class_member_property(codegen, identifier)) {
+ // Get property.
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(_gdtype_from_datatype(p_expression->get_datatype(), codegen.script));
+ gen->write_get_member(temp, identifier);
+ return temp;
+ }
+
+ // Try members.
+ if (!codegen.function_node || !codegen.function_node->is_static) {
+ // Try member variables.
+ if (codegen.script->member_indices.has(identifier)) {
+ if (codegen.script->member_indices[identifier].getter != StringName() && codegen.script->member_indices[identifier].getter != codegen.function_name) {
+ // Perform getter.
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(codegen.script->member_indices[identifier].data_type);
+ Vector args; // No argument needed.
+ gen->write_call_self(temp, codegen.script->member_indices[identifier].getter, args);
+ return temp;
+ } else {
+ // No getter or inside getter: direct member access.
+ int idx = codegen.script->member_indices[identifier].index;
+ return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::MEMBER, idx, codegen.script->get_member_type(identifier));
+ }
}
}
- scr = scr->_base;
- }
- }
+ } break;
+ case GDScriptParser::IdentifierNode::MEMBER_FUNCTION:
+ case GDScriptParser::IdentifierNode::MEMBER_SIGNAL: {
+ // Try methods and signals (can be Callable and Signal).
- // Try class constants.
- {
- GDScript *owner = codegen.script;
- while (owner) {
- GDScript *scr = owner;
+ // Search upwards through parent classes:
+ const GDScriptParser::ClassNode *base_class = codegen.class_node;
+ while (base_class != nullptr) {
+ if (base_class->has_member(identifier)) {
+ const GDScriptParser::ClassNode::Member &member = base_class->get_member(identifier);
+ if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) {
+ // Get like it was a property.
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
+ GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
+
+ gen->write_get_named(temp, identifier, self);
+ return temp;
+ }
+ }
+ base_class = base_class->base_type.class_type;
+ }
+
+ // Try in native base.
+ GDScript *scr = codegen.script;
GDScriptNativeClass *nc = nullptr;
while (scr) {
- if (scr->constants.has(identifier)) {
- return codegen.add_constant(scr->constants[identifier]); // TODO: Get type here.
- }
if (scr->native.is_valid()) {
nc = scr->native.ptr();
}
scr = scr->_base;
}
- // Class C++ integer constant.
- if (nc) {
- bool success = false;
- int64_t constant = ClassDB::get_integer_constant(nc->get_name(), identifier, &success);
- if (success) {
- return codegen.add_constant(constant);
+ if (nc && (ClassDB::has_signal(nc->get_name(), identifier) || ClassDB::has_method(nc->get_name(), identifier))) {
+ // Get like it was a property.
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
+ GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
+
+ gen->write_get_named(temp, identifier, self);
+ return temp;
+ }
+ } break;
+ case GDScriptParser::IdentifierNode::MEMBER_CONSTANT:
+ case GDScriptParser::IdentifierNode::MEMBER_CLASS: {
+ // Try class constants.
+ GDScript *owner = codegen.script;
+ while (owner) {
+ GDScript *scr = owner;
+ GDScriptNativeClass *nc = nullptr;
+ while (scr) {
+ if (scr->constants.has(identifier)) {
+ return codegen.add_constant(scr->constants[identifier]); // TODO: Get type here.
+ }
+ if (scr->native.is_valid()) {
+ nc = scr->native.ptr();
+ }
+ scr = scr->_base;
+ }
+
+ // Class C++ integer constant.
+ if (nc) {
+ bool success = false;
+ int64_t constant = ClassDB::get_integer_constant(nc->get_name(), identifier, &success);
+ if (success) {
+ return codegen.add_constant(constant);
+ }
+ }
+
+ owner = owner->_owner;
+ }
+ } break;
+ case GDScriptParser::IdentifierNode::STATIC_VARIABLE: {
+ // Try static variables.
+ GDScript *scr = codegen.script;
+ while (scr) {
+ if (scr->static_variables_indices.has(identifier)) {
+ if (scr->static_variables_indices[identifier].getter != StringName() && scr->static_variables_indices[identifier].getter != codegen.function_name) {
+ // Perform getter.
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(scr->static_variables_indices[identifier].data_type);
+ GDScriptCodeGenerator::Address class_addr(GDScriptCodeGenerator::Address::CLASS);
+ Vector args; // No argument needed.
+ gen->write_call(temp, class_addr, scr->static_variables_indices[identifier].getter, args);
+ return temp;
+ } else {
+ // No getter or inside getter: direct variable access.
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(scr->static_variables_indices[identifier].data_type);
+ GDScriptCodeGenerator::Address _class = codegen.add_constant(scr);
+ int index = scr->static_variables_indices[identifier].index;
+ gen->write_get_static_variable(temp, _class, index);
+ return temp;
+ }
+ }
+ scr = scr->_base;
+ }
+ } break;
+
+ // GLOBALS.
+ case GDScriptParser::IdentifierNode::UNDEFINED_SOURCE: {
+ // Try globals.
+ if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
+ // If it's an autoload singleton, we postpone to load it at runtime.
+ // This is so one autoload doesn't try to load another before it's compiled.
+ HashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+ if (autoloads.has(identifier) && autoloads[identifier].is_singleton) {
+ GDScriptCodeGenerator::Address global = codegen.add_temporary(_gdtype_from_datatype(in->get_datatype(), codegen.script));
+ int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
+ gen->write_store_global(global, idx);
+ return global;
+ } else {
+ int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
+ Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx];
+ return codegen.add_constant(global);
}
}
- owner = owner->_owner;
- }
- }
-
- // Try signals and methods (can be made callables).
- {
- // Search upwards through parent classes:
- const GDScriptParser::ClassNode *base_class = codegen.class_node;
- while (base_class != nullptr) {
- if (base_class->has_member(identifier)) {
- const GDScriptParser::ClassNode::Member &member = base_class->get_member(identifier);
- if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) {
- // Get like it was a property.
- GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
- GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
-
- gen->write_get_named(temp, identifier, self);
- return temp;
+ // Try global classes.
+ if (ScriptServer::is_global_class(identifier)) {
+ const GDScriptParser::ClassNode *class_node = codegen.class_node;
+ while (class_node->outer) {
+ class_node = class_node->outer;
}
- }
- base_class = base_class->base_type.class_type;
- }
- // Try in native base.
- GDScript *scr = codegen.script;
- GDScriptNativeClass *nc = nullptr;
- while (scr) {
- if (scr->native.is_valid()) {
- nc = scr->native.ptr();
- }
- scr = scr->_base;
- }
+ Ref res;
- if (nc && (ClassDB::has_signal(nc->get_name(), identifier) || ClassDB::has_method(nc->get_name(), identifier))) {
- // Get like it was a property.
- GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
- GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
-
- gen->write_get_named(temp, identifier, self);
- return temp;
- }
- }
-
- // Try globals.
- if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
- // If it's an autoload singleton, we postpone to load it at runtime.
- // This is so one autoload doesn't try to load another before it's compiled.
- HashMap autoloads = ProjectSettings::get_singleton()->get_autoload_list();
- if (autoloads.has(identifier) && autoloads[identifier].is_singleton) {
- GDScriptCodeGenerator::Address global = codegen.add_temporary(_gdtype_from_datatype(in->get_datatype(), codegen.script));
- int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
- gen->write_store_global(global, idx);
- return global;
- } else {
- int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
- Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx];
- return codegen.add_constant(global);
- }
- }
-
- // Try global classes.
- if (ScriptServer::is_global_class(identifier)) {
- const GDScriptParser::ClassNode *class_node = codegen.class_node;
- while (class_node->outer) {
- class_node = class_node->outer;
- }
-
- Ref res;
-
- if (class_node->identifier && class_node->identifier->name == identifier) {
- res = Ref(main_script);
- } else {
- String global_class_path = ScriptServer::get_global_class_path(identifier);
- if (ResourceLoader::get_resource_type(global_class_path) == "GDScript") {
- Error err = OK;
- res = GDScriptCache::get_full_script(global_class_path, err);
- if (err != OK) {
- _set_error("Can't load global class " + String(identifier), p_expression);
- r_error = ERR_COMPILATION_FAILED;
- return GDScriptCodeGenerator::Address();
+ if (class_node->identifier && class_node->identifier->name == identifier) {
+ res = Ref(main_script);
+ } else {
+ String global_class_path = ScriptServer::get_global_class_path(identifier);
+ if (ResourceLoader::get_resource_type(global_class_path) == "GDScript") {
+ Error err = OK;
+ res = GDScriptCache::get_full_script(global_class_path, err);
+ if (err != OK) {
+ _set_error("Can't load global class " + String(identifier), p_expression);
+ r_error = ERR_COMPILATION_FAILED;
+ return GDScriptCodeGenerator::Address();
+ }
+ } else {
+ res = ResourceLoader::load(global_class_path);
+ if (res.is_null()) {
+ _set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression);
+ r_error = ERR_COMPILATION_FAILED;
+ return GDScriptCodeGenerator::Address();
+ }
+ }
}
- } else {
- res = ResourceLoader::load(global_class_path);
- if (res.is_null()) {
- _set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression);
- r_error = ERR_COMPILATION_FAILED;
- return GDScriptCodeGenerator::Address();
- }
- }
- }
- return codegen.add_constant(res);
- }
+ return codegen.add_constant(res);
+ }
#ifdef TOOLS_ENABLED
- if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) {
- GDScriptCodeGenerator::Address global = codegen.add_temporary(); // TODO: Get type.
- gen->write_store_named_global(global, identifier);
- return global;
- }
+ if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) {
+ GDScriptCodeGenerator::Address global = codegen.add_temporary(); // TODO: Get type.
+ gen->write_store_named_global(global, identifier);
+ return global;
+ }
#endif
+ } break;
+ }
+
// Not found, error.
_set_error("Identifier not found: " + String(identifier), p_expression);
r_error = ERR_COMPILATION_FAILED;
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 47ceee39432..8ad2486e2b0 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1403,7 +1403,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);
@@ -1467,7 +1467,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
} break;
case GDScriptParser::Node::IDENTIFIER: {
const GDScriptParser::IdentifierNode *id = static_cast(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.
@@ -1910,7 +1910,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())) {
@@ -1924,36 +1924,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;
}
}
@@ -1968,7 +1981,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
const GDScriptParser::AssignmentNode *assign = static_cast(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(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;
}
@@ -1986,7 +1999,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(suite->parent_if->condition);
- if (type_test->operand && type_test->test_type && type_test->operand->type == GDScriptParser::Node::IDENTIFIER && static_cast(type_test->operand)->name == p_identifier) {
+ if (type_test->operand && type_test->test_type && type_test->operand->type == GDScriptParser::Node::IDENTIFIER && static_cast(type_test->operand)->name == p_identifier->name && static_cast(type_test->operand)->source == p_identifier->source) {
// Bingo.
GDScriptParser::CompletionContext c = p_context;
c.current_line = type_test->operand->start_line;
@@ -2022,8 +2035,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();
}
@@ -2048,7 +2061,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;
}
@@ -2076,14 +2089,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 parser = GDScriptCache::get_parser(script, GDScriptParserRef::INTERFACE_SOLVED, err);
@@ -2099,7 +2112,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
return true;
}
} else {
- Ref