diff --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h --- a/clang/include/clang/ExtractAPI/API.h +++ b/clang/include/clang/ExtractAPI/API.h @@ -494,21 +494,6 @@ virtual void anchor(); }; -struct ObjCCategoryModuleRecord : APIRecord { - // ObjCCategoryRecord%s are stored in and owned by APISet. - SmallVector Categories; - - ObjCCategoryModuleRecord(StringRef USR, StringRef Name) - : APIRecord(RK_ObjCCategoryModule, USR, Name) {} - - static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_ObjCCategoryModule; - } - -private: - virtual void anchor(); -}; - /// This holds information associated with Objective-C interfaces/classes. struct ObjCInterfaceRecord : ObjCContainerRecord { SymbolReference SuperClass; @@ -689,9 +674,6 @@ DeclarationFragments SubHeading, bool IsFromSystemHeader); - ObjCCategoryModuleRecord *addObjCCategoryModule(StringRef Name, - StringRef USR); - /// Create and add an Objective-C category record into the API set. /// /// Note: the caller is responsible for keeping the StringRef \p Name and @@ -819,9 +801,6 @@ const RecordMap &getObjCCategories() const { return ObjCCategories; } - const RecordMap &getObjCCategoryModule() const { - return ObjCCategoryModule; - } const RecordMap &getObjCInterfaces() const { return ObjCInterfaces; } @@ -875,7 +854,6 @@ RecordMap Enums; RecordMap Structs; RecordMap ObjCCategories; - RecordMap ObjCCategoryModule; RecordMap ObjCInterfaces; RecordMap ObjCProtocols; RecordMap Macros; diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h --- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h +++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h @@ -125,15 +125,6 @@ } } -template -static bool isExternalCategory(const T &Records, const StringRef &Name) { - for (const auto &Record : Records) { - if (Name == Record.second.get()->Name) - return false; - } - return true; -} - template bool ExtractAPIVisitorBase::VisitVarDecl(const VarDecl *Decl) { // skip function parameters. @@ -493,12 +484,13 @@ SymbolReference Interface(InterfaceDecl->getName(), API.recordUSR(InterfaceDecl)); - bool IsFromExternalModule = - isExternalCategory(API.getObjCInterfaces(), InterfaceDecl->getName()); - - if (IsFromExternalModule) - API.addObjCCategoryModule(InterfaceDecl->getName(), - API.recordUSR(InterfaceDecl)); + bool IsFromExternalModule = true; + for (const auto &Interface : API.getObjCInterfaces()) { + if (InterfaceDecl->getName() == Interface.second.get()->Name) { + IsFromExternalModule = false; + break; + } + } ObjCCategoryRecord *ObjCCategoryRecord = API.addObjCCategory( Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading, diff --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h --- a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h +++ b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h @@ -37,8 +37,6 @@ getDerived()->traverseObjCCategories(); - getDerived()->traverseObjCCategoryModule(); - getDerived()->traverseMacroDefinitionRecords(); getDerived()->traverseTypedefRecords(); @@ -79,11 +77,6 @@ getDerived()->visitObjCCategoryRecord(*Category.second); } - void traverseObjCCategoryModule() { - for (const auto &CategoryModule : API.getObjCCategoryModule()) - getDerived()->visitObjCCategoryModuleRecord(*CategoryModule.second); - } - void traverseMacroDefinitionRecords() { for (const auto &Macro : API.getMacros()) getDerived()->visitMacroDefinitionRecord(*Macro.second); @@ -112,9 +105,6 @@ /// Visit an Objective-C category record. void visitObjCCategoryRecord(const ObjCCategoryRecord &Record){}; - /// Visit an Objective-C category module record. - void visitObjCCategoryModuleRecord(const ObjCCategoryModuleRecord &Record){}; - /// Visit a macro definition record. void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record){}; diff --git a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h --- a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h +++ b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h @@ -21,6 +21,7 @@ #include "clang/ExtractAPI/APIIgnoresList.h" #include "clang/ExtractAPI/Serialization/SerializerBase.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/JSON.h" #include "llvm/Support/VersionTuple.h" #include "llvm/Support/raw_ostream.h" @@ -147,6 +148,8 @@ SymbolGraphSerializerOption Options; + llvm::StringSet<> visitedCategories; + public: /// Visit a global function record. void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record); @@ -166,9 +169,6 @@ /// Visit an Objective-C category record. void visitObjCCategoryRecord(const ObjCCategoryRecord &Record); - /// Visit an Objective-C category module record. - void visitObjCCategoryModuleRecord(const ObjCCategoryModuleRecord &Record); - /// Visit a macro definition record. void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record); diff --git a/clang/lib/ExtractAPI/API.cpp b/clang/lib/ExtractAPI/API.cpp --- a/clang/lib/ExtractAPI/API.cpp +++ b/clang/lib/ExtractAPI/API.cpp @@ -120,15 +120,6 @@ SubHeading, IsFromSystemHeader); } -ObjCCategoryModuleRecord *APISet::addObjCCategoryModule(StringRef Name, - StringRef USR) { - // Create the category record. - auto *Record = - addTopLevelRecord(USRBasedLookupTable, ObjCCategoryModule, USR, Name); - - return Record; -} - ObjCCategoryRecord *APISet::addObjCCategory( StringRef Name, StringRef USR, PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment, @@ -142,17 +133,10 @@ SubHeading, Interface, IsFromSystemHeader); Record->IsFromExternalModule = IsFromExternalModule; - // If this category is extending an external module, associate it with that - // module. - if (IsFromExternalModule) { - auto It = ObjCCategoryModule.find(Interface.USR); - if (It != ObjCCategoryModule.end()) - It->second->Categories.push_back(Record); - } else { - auto It = ObjCInterfaces.find(Interface.USR); - if (It != ObjCInterfaces.end()) - It->second->Categories.push_back(Record); - } + + auto It = ObjCInterfaces.find(Interface.USR); + if (It != ObjCInterfaces.end()) + It->second->Categories.push_back(Record); return Record; } @@ -312,7 +296,6 @@ void ObjCInstanceMethodRecord::anchor() {} void ObjCClassMethodRecord::anchor() {} void ObjCCategoryRecord::anchor() {} -void ObjCCategoryModuleRecord::anchor() {} void ObjCInterfaceRecord::anchor() {} void ObjCProtocolRecord::anchor() {} void MacroDefinitionRecord::anchor() {} diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -216,7 +216,11 @@ /// references, and the interface language name. Object serializeIdentifier(const APIRecord &Record, Language Lang) { Object Identifier; - Identifier["precise"] = Record.USR; + if (auto *CategoryRecord = + dyn_cast_or_null(&Record)) + Identifier["precise"] = CategoryRecord->Interface.USR; + else + Identifier["precise"] = Record.USR; Identifier["interfaceLanguage"] = getLanguageName(Lang); return Identifier; @@ -506,14 +510,16 @@ if (!ParentRecord) ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR); - // If the parent is a category then we need to pretend this belongs to the - // associated interface. + // If the parent is a category extended from internal module then we need to + // pretend this belongs to the associated interface. if (auto *CategoryRecord = dyn_cast_or_null(ParentRecord)) { - ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR); - CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR, - CategoryRecord->Interface.Name, - APIRecord::RK_ObjCInterface); + if (!CategoryRecord->IsFromExternalModule) { + ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR); + CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR, + CategoryRecord->Interface.Name, + APIRecord::RK_ObjCInterface); + } } // The parent record doesn't exist which means the symbol shouldn't be @@ -744,28 +750,31 @@ } } -void SymbolGraphSerializer::visitObjCCategoryModuleRecord( - const ObjCCategoryModuleRecord &Record) { - Object Obj; - serializeObject(Obj, "identifier", - serializeIdentifier(Record, API.getLanguage())); - serializeObject( - Obj, "kind", - serializeSymbolKind(APIRecord::RK_ObjCCategoryModule, API.getLanguage())); - Obj["accessLevel"] = "public"; - Symbols.emplace_back(std::move(Obj)); - - // If the category is extended from an external module, it is then member of - // that module. - for (const auto &Category : Record.Categories) - serializeRelationship(RelationshipKind::MemberOf, *Category, Record); -} - void SymbolGraphSerializer::visitObjCCategoryRecord( const ObjCCategoryRecord &Record) { if (!Record.IsFromExternalModule) return; + // Check if the current Category Record has been visited before, if not add. + if (!(visitedCategories.contains(Record.Interface.Name) > 0)) { + visitedCategories.insert(Record.Interface.Name); + Object Obj; + serializeObject(Obj, "identifier", + serializeIdentifier(Record, API.getLanguage())); + serializeObject(Obj, "kind", + serializeSymbolKind(APIRecord::RK_ObjCCategoryModule, + API.getLanguage())); + Obj["accessLevel"] = "public"; + Symbols.emplace_back(std::move(Obj)); + } + + Object Relationship; + Relationship["source"] = Record.USR; + Relationship["target"] = Record.Interface.USR; + Relationship["targetFallback"] = Record.Interface.Name; + Relationship["kind"] = getRelationshipString(RelationshipKind::MemberOf); + Relationships.emplace_back(std::move(Relationship)); + auto ObjCCategory = serializeAPIRecord(Record); if (!ObjCCategory) @@ -815,9 +824,6 @@ case APIRecord::RK_ObjCCategory: visitObjCCategoryRecord(*cast(Record)); break; - case APIRecord::RK_ObjCCategoryModule: - visitObjCCategoryModuleRecord(*cast(Record)); - break; case APIRecord::RK_MacroDefinition: visitMacroDefinitionRecord(*cast(Record)); break; diff --git a/clang/test/ExtractAPI/objc_module_category.m b/clang/test/ExtractAPI/objc_module_category.m --- a/clang/test/ExtractAPI/objc_module_category.m +++ b/clang/test/ExtractAPI/objc_module_category.m @@ -54,30 +54,41 @@ "relationships": [ { "kind": "memberOf", - "source": "c:objc(cs)NSString(im)method1", - "target": "c:objc(cy)NSString@Category1", - "targetFallback": "Category1" + "source": "c:objc(cy)NSString@Category1", + "target": "c:objc(cs)NSString", + "targetFallback": "NSString" }, { "kind": "memberOf", - "source": "c:objc(cs)NSString(im)method2", - "target": "c:objc(cy)NSString@Category2", - "targetFallback": "Category2" + "source": "c:objc(cs)NSString(im)method1", + "target": "c:objc(cy)NSString@Category1", + "targetFallback": "Category1" }, { "kind": "memberOf", - "source": "c:objc(cy)NSString@Category1", + "source": "c:objc(cy)NSString@Category2", "target": "c:objc(cs)NSString", "targetFallback": "NSString" }, { "kind": "memberOf", - "source": "c:objc(cy)NSString@Category2", - "target": "c:objc(cs)NSString", - "targetFallback": "NSString" + "source": "c:objc(cs)NSString(im)method2", + "target": "c:objc(cy)NSString@Category2", + "targetFallback": "Category2" } ], "symbols": [ + { + "accessLevel": "public", + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)NSString" + }, + "kind": { + "displayName": "Module Extension", + "identifier": "objective-c.module.extension" + } + }, { "accessLevel": "public", "declarationFragments": [ @@ -126,7 +137,7 @@ }, "identifier": { "interfaceLanguage": "objective-c", - "precise": "c:objc(cy)NSString@Category1" + "precise": "c:objc(cs)NSString" }, "kind": { "displayName": "Class Extension", @@ -227,7 +238,7 @@ "title": "method1" }, "pathComponents": [ - "NSString", + "Category1", "method1" ] }, @@ -279,7 +290,7 @@ }, "identifier": { "interfaceLanguage": "objective-c", - "precise": "c:objc(cy)NSString@Category2" + "precise": "c:objc(cs)NSString" }, "kind": { "displayName": "Class Extension", @@ -380,20 +391,9 @@ "title": "method2" }, "pathComponents": [ - "NSString", + "Category2", "method2" ] - }, - { - "accessLevel": "public", - "identifier": { - "interfaceLanguage": "objective-c", - "precise": "c:objc(cs)NSString" - }, - "kind": { - "displayName": "Module Extension", - "identifier": "objective-c.module.extension" - } } ] } diff --git a/clang/test/ExtractAPI/objc_various_categories.m b/clang/test/ExtractAPI/objc_various_categories.m --- a/clang/test/ExtractAPI/objc_various_categories.m +++ b/clang/test/ExtractAPI/objc_various_categories.m @@ -25,13 +25,17 @@ @end @interface MyClass2 (MyCategory2) -- (int) SomeMethod; +- (int) SomeMethod2; @end -@interface NSString (Category) +@interface NSString (Category1) -(void) StringMethod; @end +@interface NSString (Category2) +-(void) StringMethod2; +@end + //--- myclass_1.h @interface MyClass1 @end @@ -74,27 +78,39 @@ }, { "kind": "memberOf", - "source": "c:objc(cs)MyClass2(im)SomeMethod", + "source": "c:objc(cy)MyClass2@MyCategory2", + "target": "c:objc(cs)MyClass2", + "targetFallback": "MyClass2" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)MyClass2(im)SomeMethod2", "target": "c:objc(cy)MyClass2@MyCategory2", "targetFallback": "MyCategory2" }, { "kind": "memberOf", - "source": "c:objc(cs)NSString(im)StringMethod", - "target": "c:objc(cy)NSString@Category", - "targetFallback": "Category" + "source": "c:objc(cy)NSString@Category1", + "target": "c:objc(cs)NSString", + "targetFallback": "NSString" }, { "kind": "memberOf", - "source": "c:objc(cy)MyClass2@MyCategory2", - "target": "c:objc(cs)MyClass2", - "targetFallback": "MyClass2" + "source": "c:objc(cs)NSString(im)StringMethod", + "target": "c:objc(cy)NSString@Category1", + "targetFallback": "Category1" }, { "kind": "memberOf", - "source": "c:objc(cy)NSString@Category", + "source": "c:objc(cy)NSString@Category2", "target": "c:objc(cs)NSString", "targetFallback": "NSString" + }, + { + "kind": "memberOf", + "source": "c:objc(cs)NSString(im)StringMethod2", + "target": "c:objc(cy)NSString@Category2", + "targetFallback": "Category2" } ], "symbols": [ @@ -221,6 +237,17 @@ "SomeMethod" ] }, + { + "accessLevel": "public", + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)MyClass2" + }, + "kind": { + "displayName": "Module Extension", + "identifier": "objective-c.module.extension" + } + }, { "accessLevel": "public", "declarationFragments": [ @@ -252,7 +279,7 @@ ], "identifier": { "interfaceLanguage": "objective-c", - "precise": "c:objc(cy)MyClass2@MyCategory2" + "precise": "c:objc(cs)MyClass2" }, "kind": { "displayName": "Class Extension", @@ -302,7 +329,7 @@ }, { "kind": "identifier", - "spelling": "SomeMethod" + "spelling": "SomeMethod2" }, { "kind": "text", @@ -320,7 +347,7 @@ }, "identifier": { "interfaceLanguage": "objective-c", - "precise": "c:objc(cs)MyClass2(im)SomeMethod" + "precise": "c:objc(cs)MyClass2(im)SomeMethod2" }, "kind": { "displayName": "Instance Method", @@ -337,7 +364,7 @@ "navigator": [ { "kind": "identifier", - "spelling": "SomeMethod" + "spelling": "SomeMethod2" } ], "subHeading": [ @@ -347,16 +374,27 @@ }, { "kind": "identifier", - "spelling": "SomeMethod" + "spelling": "SomeMethod2" } ], - "title": "SomeMethod" + "title": "SomeMethod2" }, "pathComponents": [ - "MyClass2", - "SomeMethod" + "MyCategory2", + "SomeMethod2" ] }, + { + "accessLevel": "public", + "identifier": { + "interfaceLanguage": "objective-c", + "precise": "c:objc(cs)NSString" + }, + "kind": { + "displayName": "Module Extension", + "identifier": "objective-c.module.extension" + } + }, { "accessLevel": "public", "declarationFragments": [ @@ -379,7 +417,7 @@ }, { "kind": "identifier", - "spelling": "Category" + "spelling": "Category1" }, { "kind": "text", @@ -388,7 +426,7 @@ ], "identifier": { "interfaceLanguage": "objective-c", - "precise": "c:objc(cy)NSString@Category" + "precise": "c:objc(cs)NSString" }, "kind": { "displayName": "Class Extension", @@ -405,19 +443,19 @@ "navigator": [ { "kind": "identifier", - "spelling": "Category" + "spelling": "Category1" } ], "subHeading": [ { "kind": "identifier", - "spelling": "Category" + "spelling": "Category1" } ], - "title": "NSString (Category)" + "title": "NSString (Category1)" }, "pathComponents": [ - "Category" + "Category1" ] }, { @@ -489,31 +527,145 @@ "title": "StringMethod" }, "pathComponents": [ - "NSString", + "Category1", "StringMethod" ] }, { "accessLevel": "public", + "declarationFragments": [ + { + "kind": "keyword", + "spelling": "@interface" + }, + { + "kind": "text", + "spelling": " " + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:objc(cs)NSString", + "spelling": "NSString" + }, + { + "kind": "text", + "spelling": " (" + }, + { + "kind": "identifier", + "spelling": "Category2" + }, + { + "kind": "text", + "spelling": ")" + } + ], "identifier": { "interfaceLanguage": "objective-c", - "precise": "c:objc(cs)MyClass2" + "precise": "c:objc(cs)NSString" }, "kind": { - "displayName": "Module Extension", - "identifier": "objective-c.module.extension" - } + "displayName": "Class Extension", + "identifier": "objective-c.class.extension" + }, + "location": { + "position": { + "character": 12, + "line": 17 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "Category2" + } + ], + "subHeading": [ + { + "kind": "identifier", + "spelling": "Category2" + } + ], + "title": "NSString (Category2)" + }, + "pathComponents": [ + "Category2" + ] }, { "accessLevel": "public", + "declarationFragments": [ + { + "kind": "text", + "spelling": "- (" + }, + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + }, + { + "kind": "text", + "spelling": ") " + }, + { + "kind": "identifier", + "spelling": "StringMethod2" + }, + { + "kind": "text", + "spelling": ";" + } + ], + "functionSignature": { + "returns": [ + { + "kind": "typeIdentifier", + "preciseIdentifier": "c:v", + "spelling": "void" + } + ] + }, "identifier": { "interfaceLanguage": "objective-c", - "precise": "c:objc(cs)NSString" + "precise": "c:objc(cs)NSString(im)StringMethod2" }, "kind": { - "displayName": "Module Extension", - "identifier": "objective-c.module.extension" - } + "displayName": "Instance Method", + "identifier": "objective-c.method" + }, + "location": { + "position": { + "character": 1, + "line": 18 + }, + "uri": "file://INPUT_DIR/input.h" + }, + "names": { + "navigator": [ + { + "kind": "identifier", + "spelling": "StringMethod2" + } + ], + "subHeading": [ + { + "kind": "text", + "spelling": "- " + }, + { + "kind": "identifier", + "spelling": "StringMethod2" + } + ], + "title": "StringMethod2" + }, + "pathComponents": [ + "Category2", + "StringMethod2" + ] } ] }