summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitrii Maganov <vonagam@gmail.com>2023-03-08 22:06:29 +0200
committerDmitrii Maganov <vonagam@gmail.com>2023-03-13 01:40:13 +0200
commit4e34cf238aeff209f5823685d7b66ae8d66118cb (patch)
treef1baec0d9450fc2c550f2a8ad9c9a8012802d9d6
parent550a7798510810d238b733a54f69da71b2a2d152 (diff)
downloadredot-engine-4e34cf238aeff209f5823685d7b66ae8d66118cb.tar.gz
GDScript: Change parser representation of class extends
-rw-r--r--modules/gdscript/gdscript.cpp6
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp32
-rw-r--r--modules/gdscript/gdscript_editor.cpp4
-rw-r--r--modules/gdscript/gdscript_parser.cpp6
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.gd8
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.out2
10 files changed, 43 insertions, 26 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 1a1d021dbc..2646c1ad15 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -2483,7 +2483,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
subclass = nullptr;
break;
} else {
- Vector<StringName> extend_classes = subclass->extends;
+ Vector<GDScriptParser::IdentifierNode *> extend_classes = subclass->extends;
Ref<FileAccess> subfile = FileAccess::open(subclass->extends_path, FileAccess::READ);
if (subfile.is_null()) {
@@ -2513,7 +2513,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
}
const GDScriptParser::ClassNode *inner_class = subclass->members[i].m_class;
- if (inner_class->identifier->name == extend_classes[0]) {
+ if (inner_class->identifier->name == extend_classes[0]->name) {
extend_classes.remove_at(0);
found = true;
subclass = inner_class;
@@ -2527,7 +2527,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
}
}
} else if (subclass->extends.size() == 1) {
- *r_base_type = subclass->extends[0];
+ *r_base_type = subclass->extends[0]->name;
subclass = nullptr;
} else {
break;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 38d5ae6b77..df2fe0a537 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -415,7 +415,8 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
push_error("Could not resolve an empty super class path.", p_class);
return ERR_PARSE_ERROR;
}
- const StringName &name = p_class->extends[extends_index++];
+ GDScriptParser::IdentifierNode *id = p_class->extends[extends_index++];
+ const StringName &name = id->name;
base.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
if (ScriptServer::is_global_class(name)) {
@@ -426,13 +427,13 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
} else {
Ref<GDScriptParserRef> base_parser = get_parser_for(base_path);
if (base_parser.is_null()) {
- push_error(vformat(R"(Could not resolve super class "%s".)", name), p_class);
+ push_error(vformat(R"(Could not resolve super class "%s".)", name), id);
return ERR_PARSE_ERROR;
}
Error err = base_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err != OK) {
- push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
+ push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), id);
return err;
}
base = base_parser->get_parser()->head->get_datatype();
@@ -440,19 +441,19 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
} else if (ProjectSettings::get_singleton()->has_autoload(name) && ProjectSettings::get_singleton()->get_autoload(name).is_singleton) {
const ProjectSettings::AutoloadInfo &info = ProjectSettings::get_singleton()->get_autoload(name);
if (info.path.get_extension().to_lower() != GDScriptLanguage::get_singleton()->get_extension()) {
- push_error(vformat(R"(Singleton %s is not a GDScript.)", info.name), p_class);
+ push_error(vformat(R"(Singleton %s is not a GDScript.)", info.name), id);
return ERR_PARSE_ERROR;
}
Ref<GDScriptParserRef> info_parser = get_parser_for(info.path);
if (info_parser.is_null()) {
- push_error(vformat(R"(Could not parse singleton from "%s".)", info.path), p_class);
+ push_error(vformat(R"(Could not parse singleton from "%s".)", info.path), id);
return ERR_PARSE_ERROR;
}
Error err = info_parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
if (err != OK) {
- push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
+ push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), id);
return err;
}
base = info_parser->get_parser()->head->get_datatype();
@@ -467,7 +468,7 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
for (GDScriptParser::ClassNode *look_class : script_classes) {
if (look_class->identifier && look_class->identifier->name == name) {
if (!look_class->get_datatype().is_set()) {
- Error err = resolve_class_inheritance(look_class, p_class);
+ Error err = resolve_class_inheritance(look_class, id);
if (err) {
return err;
}
@@ -477,7 +478,7 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
break;
}
if (look_class->has_member(name)) {
- resolve_class_member(look_class, name, p_class);
+ resolve_class_member(look_class, name, id);
base = look_class->get_member(name).get_datatype();
found = true;
break;
@@ -485,27 +486,26 @@ Error GDScriptAnalyzer::resolve_class_inheritance(GDScriptParser::ClassNode *p_c
}
if (!found) {
- push_error(vformat(R"(Could not find base class "%s".)", name), p_class);
+ push_error(vformat(R"(Could not find base class "%s".)", name), id);
return ERR_PARSE_ERROR;
}
}
}
for (int index = extends_index; index < p_class->extends.size(); index++) {
+ GDScriptParser::IdentifierNode *id = p_class->extends[index];
+
if (base.kind != GDScriptParser::DataType::CLASS) {
- push_error(R"(Super type "%s" is not a GDScript. Cannot get nested types.)", p_class);
+ push_error(vformat(R"(Cannot get nested types for extension from non-GDScript type "%s".)", base.to_string()), id);
return ERR_PARSE_ERROR;
}
- // TODO: Extends could use identifier nodes. That way errors can be pointed out properly and it can be used here.
- GDScriptParser::IdentifierNode *id = parser->alloc_node<GDScriptParser::IdentifierNode>();
- id->name = p_class->extends[index];
-
reduce_identifier_from_base(id, &base);
-
GDScriptParser::DataType id_type = id->get_datatype();
+
if (!id_type.is_set()) {
- push_error(vformat(R"(Could not find type "%s" under base "%s".)", id->name, base.to_string()), p_class);
+ push_error(vformat(R"(Could not find nested type "%s".)", id->name), id);
+ return ERR_PARSE_ERROR;
}
base = id_type;
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 536cb344f4..f3a86522ae 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -3368,10 +3368,10 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
if (context.current_class && context.current_class->extends.size() > 0) {
bool success = false;
- ClassDB::get_integer_constant(context.current_class->extends[0], p_symbol, &success);
+ ClassDB::get_integer_constant(context.current_class->extends[0]->name, p_symbol, &success);
if (success) {
r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_CONSTANT;
- r_result.class_name = context.current_class->extends[0];
+ r_result.class_name = context.current_class->extends[0]->name;
r_result.class_member = p_symbol;
return OK;
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 00a3e41c2b..e2a37ab6e9 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -712,14 +712,14 @@ void GDScriptParser::parse_extends() {
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected superclass name after "extends".)")) {
return;
}
- current_class->extends.push_back(previous.literal);
+ current_class->extends.push_back(parse_identifier());
while (match(GDScriptTokenizer::Token::PERIOD)) {
make_completion_context(COMPLETION_INHERIT_TYPE, current_class, chain_index++);
if (!consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected superclass name after ".".)")) {
return;
}
- current_class->extends.push_back(previous.literal);
+ current_class->extends.push_back(parse_identifier());
}
}
@@ -4479,7 +4479,7 @@ void GDScriptParser::TreePrinter::print_class(ClassNode *p_class) {
} else {
first = false;
}
- push_text(p_class->extends[i]);
+ push_text(p_class->extends[i]->name);
}
}
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 346c9bc45d..29841ab060 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -710,7 +710,7 @@ public:
bool extends_used = false;
bool onready_used = false;
String extends_path;
- Vector<StringName> extends; // List for indexing: extends A.B.C
+ Vector<IdentifierNode *> extends; // List for indexing: extends A.B.C
DataType base_type;
String fqcn; // Fully-qualified class name. Identifies uniquely any class in the project.
#ifdef TOOLS_ENABLED
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 146ed10ceb..2ed444c7ad 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -717,7 +717,7 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
class_api["path"] = path;
Array extends_class;
for (int i = 0; i < p_class->extends.size(); i++) {
- extends_class.append(String(p_class->extends[i]));
+ extends_class.append(String(p_class->extends[i]->name));
}
class_api["extends_class"] = extends_class;
class_api["extends_file"] = String(p_class->extends_path);
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.gd b/modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.gd
new file mode 100644
index 0000000000..54cf4d89ec
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.gd
@@ -0,0 +1,5 @@
+class Foo extends RefCounted.Bar:
+ pass
+
+func test():
+ print('not ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.out b/modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.out
new file mode 100644
index 0000000000..386d6261c6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/extend_non_gdscript_nested.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot get nested types for extension from non-GDScript type "RefCounted".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.gd b/modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.gd
new file mode 100644
index 0000000000..0f7d584edb
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.gd
@@ -0,0 +1,8 @@
+class Foo:
+ pass
+
+class Bar extends Foo.Baz:
+ pass
+
+func test():
+ print('not ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.out b/modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.out
new file mode 100644
index 0000000000..42873056f2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/extend_unknown.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not find nested type "Baz".