LSP: Fix crash in find_usages_in_file by correctly resolving annotation names

This commit is contained in:
HolonProduction
2026-04-26 19:02:11 +02:00
parent 6d6e822c68
commit 0813b357d2
7 changed files with 126 additions and 54 deletions
@@ -423,7 +423,7 @@ bool GDScriptWorkspace::can_rename(const LSP::TextDocumentPositionParams &p_doc_
String path = get_file_path(p_doc_pos.textDocument.uri);
const ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(path);
if (parser) {
_ALLOW_DISCARD_ parser->get_identifier_under_position(p_doc_pos.position, r_range);
_ALLOW_DISCARD_ parser->get_symbol_name_under_position(p_doc_pos.position, r_range);
r_symbol = *reference_symbol;
return true;
}
@@ -453,7 +453,7 @@ Vector<LSP::Location> GDScriptWorkspace::find_usages_in_file(const LSP::Document
params.position.character = character;
LSP::Range range;
String identifier_under_cursor = parser->get_identifier_under_position(params.position, range);
String identifier_under_cursor = parser->get_symbol_name_under_position(params.position, range);
if (identifier_under_cursor == identifier) {
const LSP::DocumentSymbol *other_symbol = resolve_symbol(params);
@@ -468,7 +468,14 @@ Vector<LSP::Location> GDScriptWorkspace::find_usages_in_file(const LSP::Document
}
}
character = line.find(identifier, range.end.character);
if (identifier_under_cursor.length() < identifier.length()) {
// `get_symbol_name_under_position` is supposed to recognize all possible symbol names. Since a simple string search already confirmed
// the presence of `p_symbol.name` in the text, this case has to be a bug.
ERR_PRINT(vformat("LSP Bug, please report. \"get_symbol_name_under_position\" did not correctly resolve \"%s\"", identifier));
character = line.find(identifier, character + 1);
} else {
character = line.find(identifier, range.end.character);
}
}
}
}
@@ -641,29 +648,30 @@ const LSP::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const LSP::TextDocu
const ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(path);
if (parser) {
String symbol_identifier = p_symbol_name;
if (symbol_identifier.get_slice_count("(") > 0) {
symbol_identifier = symbol_identifier.get_slicec('(', 0);
String symbol_name = p_symbol_name;
if (symbol_name.get_slice_count("(") > 0) {
symbol_name = symbol_name.get_slicec('(', 0);
}
LSP::Position pos = p_doc_pos.position;
if (symbol_identifier.is_empty()) {
if (symbol_name.is_empty()) {
LSP::Range range;
symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, range);
symbol_name = parser->get_symbol_name_under_position(p_doc_pos.position, range);
pos.character = range.end.character;
}
if (!symbol_identifier.is_empty()) {
if (ScriptServer::is_global_class(symbol_identifier)) {
String class_path = ScriptServer::get_global_class_path(symbol_identifier);
if (!symbol_name.is_empty()) {
if (ScriptServer::is_global_class(symbol_name)) {
String class_path = ScriptServer::get_global_class_path(symbol_name);
symbol = get_script_symbol(class_path);
} else {
ScriptLanguage::LookupResult ret;
if (symbol_identifier == "new" && parser->get_lines()[p_doc_pos.position.line].remove_chars(" \t").contains("new(")) {
symbol_identifier = "_init";
// TODO: `lookup_code` should already account for this. We might be able to simplify code here.
if (symbol_name == "new" && parser->get_lines()[p_doc_pos.position.line].remove_chars(" \t").contains("new(")) {
symbol_name = "_init";
}
if (OK == GDScriptLanguage::get_singleton()->lookup_code(parser->get_text_for_lookup_symbol(pos, symbol_identifier, p_func_required), symbol_identifier, path, nullptr, ret)) {
if (OK == GDScriptLanguage::get_singleton()->lookup_code(parser->get_text_for_lookup_symbol(pos, symbol_name, p_func_required), symbol_name, path, nullptr, ret)) {
if (ret.location >= 0) {
String target_script_path = path;
if (ret.script.is_valid()) {
@@ -674,13 +682,13 @@ const LSP::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const LSP::TextDocu
const ExtendGDScriptParser *target_parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(target_script_path);
if (target_parser) {
symbol = target_parser->get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(ret.location), symbol_identifier);
symbol = target_parser->get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(ret.location), symbol_name);
if (symbol) {
switch (symbol->kind) {
case LSP::SymbolKind::Function: {
if (symbol->name != symbol_identifier) {
symbol = get_parameter_symbol(symbol, symbol_identifier);
if (symbol->name != symbol_name) {
symbol = get_parameter_symbol(symbol, symbol_name);
}
} break;
}
@@ -688,15 +696,15 @@ const LSP::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const LSP::TextDocu
}
} else {
String member = ret.class_member;
if (member.is_empty() && symbol_identifier != ret.class_name) {
member = symbol_identifier;
if (member.is_empty() && symbol_name != ret.class_name) {
member = symbol_name;
}
symbol = get_native_symbol(ret.class_name, member);
}
} else {
symbol = get_local_symbol_at(parser, symbol_identifier, p_doc_pos.position);
symbol = get_local_symbol_at(parser, symbol_name, p_doc_pos.position);
if (!symbol) {
symbol = parser->get_member_symbol(symbol_identifier);
symbol = parser->get_member_symbol(symbol_name);
}
}
}