Quellcode durchsuchen

LibIDL: Emit an error when two decls of the same function are present

Duplicates can show up when copy-pasting IDL snippets into existing IDL
files, and the resulting error is extremely useless and misleading.
This commit makes it so the parser catches these cases, and emits a more
helpful error like "Overload set 'instantiate' contains multiple
identical declarations".
Ali Mohammad Pur vor 1 Jahr
Ursprung
Commit
971e466521

+ 28 - 1
Userland/Libraries/LibIDL/IDLParser.cpp

@@ -372,6 +372,7 @@ Vector<Parameter> Parser::parse_parameters()
 
 Function Parser::parse_function(HashMap<ByteString, ByteString>& extended_attributes, Interface& interface, IsSpecialOperation is_special_operation)
 {
+    auto position = lexer.current_position();
     bool static_ = false;
     if (lexer.consume_specific("static"sv)) {
         static_ = true;
@@ -388,7 +389,7 @@ Function Parser::parse_function(HashMap<ByteString, ByteString>& extended_attrib
     consume_whitespace();
     assert_specific(';');
 
-    Function function { move(return_type), name, move(parameters), move(extended_attributes), {}, false };
+    Function function { move(return_type), name, move(parameters), move(extended_attributes), position, {}, false };
 
     // "Defining a special operation with an identifier is equivalent to separating the special operation out into its own declaration without an identifier."
     if (is_special_operation == IsSpecialOperation::No || (is_special_operation == IsSpecialOperation::Yes && !name.is_empty())) {
@@ -1112,6 +1113,32 @@ Interface& Parser::parse()
     }
     // FIXME: Add support for overloading constructors
 
+    // Check overload sets for repeated instances of the same function
+    // as these will produce very cryptic errors if left alone.
+    for (auto& overload_set : interface.overload_sets) {
+        auto& functions = overload_set.value;
+        for (size_t i = 0; i < functions.size(); ++i) {
+            for (size_t j = i + 1; j < functions.size(); ++j) {
+                if (functions[i].parameters.size() != functions[j].parameters.size())
+                    continue;
+                auto same = true;
+                for (size_t k = 0; k < functions[i].parameters.size(); ++k) {
+                    if (functions[i].parameters[k].type->is_distinguishable_from(interface, functions[j].parameters[k].type)) {
+                        same = false;
+                        break;
+                    }
+                }
+                if (same) {
+                    report_parsing_error(
+                        ByteString::formatted("Overload set '{}' contains multiple identical declarations", overload_set.key),
+                        filename,
+                        input,
+                        functions[j].source_position.offset);
+                }
+            }
+        }
+    }
+
     if (interface.will_generate_code())
         interface.required_imported_paths.set(this_module);
     interface.imported_modules = move(imports);

+ 1 - 1
Userland/Libraries/LibIDL/IDLParser.h

@@ -61,7 +61,7 @@ private:
     ByteString import_base_path;
     ByteString filename;
     StringView input;
-    GenericLexer lexer;
+    LineTrackingLexer lexer;
 
     HashTable<NonnullOwnPtr<Interface>>& top_level_interfaces();
     HashTable<NonnullOwnPtr<Interface>> interfaces;

+ 1 - 0
Userland/Libraries/LibIDL/Types.h

@@ -158,6 +158,7 @@ struct Function {
     ByteString name;
     Vector<Parameter> parameters;
     HashMap<ByteString, ByteString> extended_attributes;
+    LineTrackingLexer::Position source_position;
     size_t overload_index { 0 };
     bool is_overloaded { false };