From ea1cb8fe677c8dab7757a7fe087a57fee8ec3e5a Mon Sep 17 00:00:00 2001 From: voylin Date: Fri, 19 Dec 2025 15:20:18 +0900 Subject: [PATCH] Add columns to Language Server --- core/object/script_language.h | 3 +- modules/gdscript/gdscript.cpp | 8 ++--- modules/gdscript/gdscript_editor.cpp | 8 ++--- modules/gdscript/gdscript_parser.cpp | 18 ++++++++-- modules/gdscript/gdscript_parser.h | 17 ++++++--- modules/gdscript/gdscript_tokenizer.h | 14 +++++--- modules/gdscript/gdscript_warning.h | 5 ++- .../gdscript_extend_parser.cpp | 35 +++++++------------ .../gdscript/tests/gdscript_test_runner.cpp | 2 +- modules/gdscript/tests/test_gdscript.cpp | 8 ++--- 10 files changed, 68 insertions(+), 50 deletions(-) diff --git a/core/object/script_language.h b/core/object/script_language.h index aef6f6046dd..633e9e52d4e 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -222,7 +222,8 @@ public: /* EDITOR FUNCTIONS */ struct Warning { - int start_line = -1, end_line = -1; + int start_line = 0; + int end_line = 0; int code; String string_code; String message; diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 0c7409007f2..b7617773375 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -820,10 +820,10 @@ Error GDScript::reload(bool p_keep_state) { } if (err) { if (EngineDebugger::is_active()) { - GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message); + GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().start_line, "Parser Error: " + parser.get_errors().front()->get().message); } // TODO: Show all error messages. - _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT); + _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().start_line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT); reloading = false; return ERR_PARSE_ERROR; } @@ -833,12 +833,12 @@ Error GDScript::reload(bool p_keep_state) { if (err) { if (EngineDebugger::is_active()) { - GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message); + GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().start_line, "Parser Error: " + parser.get_errors().front()->get().message); } const List::Element *e = parser.get_errors().front(); while (e != nullptr) { - _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().line, ("Parse Error: " + e->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT); + _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().start_line, ("Parse Error: " + e->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT); e = e->next(); } reloading = false; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index e4467513e66..b7ec6fa136e 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -169,8 +169,8 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li for (const GDScriptParser::ParserError &pe : parser.get_errors()) { ScriptLanguage::ScriptError e; e.path = p_path; - e.line = pe.line; - e.column = pe.column; + e.line = pe.start_line; + e.column = pe.start_column; e.message = pe.message; r_errors->push_back(e); } @@ -180,8 +180,8 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li 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.line = pe.start_line; + e.column = pe.start_column; e.message = pe.message; r_errors->push_back(e); } diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 907b44a3e0c..912a5ca771b 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -235,12 +235,22 @@ void GDScriptParser::push_error(const String &p_message, const Node *p_origin) { // TODO: Improve error reporting by pointing at source code. // TODO: Errors might point at more than one place at once (e.g. show previous declaration). panic_mode = true; - // TODO: Improve positional information. + ParserError err; + err.message = p_message; + if (p_origin == nullptr) { - errors.push_back({ p_message, previous.start_line, previous.start_column }); + err.start_line = previous.start_line; + err.start_column = previous.start_column; + err.end_line = previous.end_line; + err.end_column = previous.end_column; } else { - errors.push_back({ p_message, p_origin->start_line, p_origin->start_column }); + err.start_line = p_origin->start_line; + err.start_column = p_origin->start_column; + err.end_line = p_origin->end_line; + err.end_column = p_origin->end_column; } + + errors.push_back(err); } #ifdef DEBUG_ENABLED @@ -279,7 +289,9 @@ void GDScriptParser::apply_pending_warnings() { warning.code = pw.code; warning.symbols = pw.symbols; warning.start_line = pw.source->start_line; + warning.start_column = pw.source->start_column; warning.end_line = pw.source->end_line; + warning.end_column = pw.source->end_column; if (pw.treated_as_error) { push_error(warning.get_message() + String(" (Warning treated as error.)"), pw.source); diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 2427481a151..0b2e790e066 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -269,7 +269,10 @@ public: // }; // Type type = NO_ERROR; String message; - int line = 0, column = 0; + int start_line = 0; + int start_column = 0; + int end_line = 0; + int end_column = 0; }; #ifdef TOOLS_ENABLED @@ -337,8 +340,10 @@ public: }; Type type = NONE; - int start_line = 0, end_line = 0; - int start_column = 0, end_column = 0; + int start_line = 0; + int start_column = 0; + int end_line = 0; + int end_column = 0; Node *next = nullptr; List annotations; @@ -1108,8 +1113,10 @@ public: StringName name; FunctionNode *source_function = nullptr; - int start_line = 0, end_line = 0; - int start_column = 0, end_column = 0; + int start_line = 0; + int start_column = 0; + int end_line = 0; + int end_column = 0; DataType get_datatype() const; String get_name() const; diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index a152529c60a..4133db8ff06 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -165,7 +165,10 @@ public: Type type = EMPTY; Variant literal; - int start_line = 0, end_line = 0, start_column = 0, end_column = 0; + int start_line = 0; + int start_column = 0; + int end_line = 0; + int end_column = 0; CursorPlace cursor_place = CURSOR_NONE; String source; @@ -224,13 +227,16 @@ class GDScriptTokenizerText : public GDScriptTokenizer { String source; const char32_t *_source = nullptr; const char32_t *_current = nullptr; - int line = -1, column = -1; - int cursor_line = -1, cursor_column = -1; + int line = 0; + int column = 0; + int cursor_line = -1; + int cursor_column = -1; int tab_size = 4; // Keep track of multichar tokens. const char32_t *_start = nullptr; - int start_line = 0, start_column = 0; + int start_line = 0; + int start_column = 0; // Info cache. bool line_continuation = false; // Whether this line is a continuation of the previous, like when using '\'. diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h index e4f22c85ba6..eae1013f095 100644 --- a/modules/gdscript/gdscript_warning.h +++ b/modules/gdscript/gdscript_warning.h @@ -158,7 +158,10 @@ public: static_assert(std_size(default_warning_levels) == WARNING_MAX, "Amount of default levels does not match the amount of warnings."); Code code = WARNING_MAX; - int start_line = -1, end_line = -1; + int start_line = 0; + int start_column = 0; + int end_line = 0; + int end_column = 0; Vector symbols; String get_name() const; diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 5c684c84bdb..86a5b04b79a 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -135,18 +135,12 @@ void ExtendGDScriptParser::update_diagnostics() { diagnostic.severity = LSP::DiagnosticSeverity::Error; diagnostic.message = error.message; diagnostic.source = "gdscript"; - diagnostic.code = -1; - LSP::Range range; - LSP::Position pos; - const PackedStringArray line_array = get_lines(); - int line = CLAMP(LINE_NUMBER_TO_INDEX(error.line), 0, line_array.size() - 1); - const String &line_text = line_array[line]; - pos.line = line; - pos.character = line_text.length() - line_text.strip_edges(true, false).length(); - range.start = pos; - range.end = range.start; - range.end.character = line_text.strip_edges(false).length(); - diagnostic.range = range; + + GodotRange godot_range( + GodotPosition(error.start_line, error.start_column), + GodotPosition(error.end_line, error.end_column)); + + diagnostic.range = godot_range.to_lsp(get_lines()); diagnostics.push_back(diagnostic); } @@ -156,17 +150,12 @@ void ExtendGDScriptParser::update_diagnostics() { diagnostic.severity = LSP::DiagnosticSeverity::Warning; diagnostic.message = "(" + warning.get_name() + "): " + warning.get_message(); diagnostic.source = "gdscript"; - diagnostic.code = warning.code; - LSP::Range range; - LSP::Position pos; - int line = LINE_NUMBER_TO_INDEX(warning.start_line); - const String &line_text = get_lines()[line]; - pos.line = line; - pos.character = line_text.length() - line_text.strip_edges(true, false).length(); - range.start = pos; - range.end = pos; - range.end.character = line_text.strip_edges(false).length(); - diagnostic.range = range; + + GodotRange godot_range( + GodotPosition(warning.start_line, warning.start_column), + GodotPosition(warning.end_line, warning.end_column)); + + diagnostic.range = godot_range.to_lsp(get_lines()); diagnostics.push_back(diagnostic); } } diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index 07861790f25..be40cf35d93 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -575,7 +575,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { StringBuilder error_string; for (const GDScriptParser::ParserError &error : parser.get_errors()) { - error_string.append(vformat(">> ERROR at line %d: %s\n", error.line, error.message)); + error_string.append(vformat(">> ERROR at line %d: %s\n", error.start_line, error.message)); } result.output += error_string.as_string(); if (!p_is_generating) { diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index bde44d7dbf6..2ffe020396b 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -175,7 +175,7 @@ static void test_parser(const String &p_code, const String &p_script_path, const if (err != OK) { const List &errors = parser.get_errors(); for (const GDScriptParser::ParserError &error : errors) { - print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); + print_line(vformat("%02d:%02d: %s", error.start_line, error.start_column, error.message)); } } @@ -185,7 +185,7 @@ static void test_parser(const String &p_code, const String &p_script_path, const if (err != OK) { const List &errors = parser.get_errors(); for (const GDScriptParser::ParserError &error : errors) { - print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); + print_line(vformat("%02d:%02d: %s", error.start_line, error.start_column, error.message)); } } @@ -261,7 +261,7 @@ static void test_compiler(const String &p_code, const String &p_script_path, con print_line("Error in parser:"); const List &errors = parser.get_errors(); for (const GDScriptParser::ParserError &error : errors) { - print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); + print_line(vformat("%02d:%02d: %s", error.start_line, error.start_column, error.message)); } return; } @@ -273,7 +273,7 @@ static void test_compiler(const String &p_code, const String &p_script_path, con print_line("Error in analyzer:"); const List &errors = parser.get_errors(); for (const GDScriptParser::ParserError &error : errors) { - print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message)); + print_line(vformat("%02d:%02d: %s", error.start_line, error.start_column, error.message)); } return; }