Ruturaj4 updated this revision to Diff 546074.
Ruturaj4 added a comment.
- [clang][ExtractAPI] Add support for Objective-C categories
- [clang][ExtractAPI] Add support for Objective-C categories
1. Updating D152770 <https://reviews.llvm.org/D152770>: [clang][ExtractAPI] Add
support for Objective-C categories #
2. Enter a brief description of the changes included in this update.
3. The first line is used as subject, next lines as comment. #
4. If you intended to create a new revision, use:
5. $ arc diff --create
Upload the correct patch and update.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D152770/new/
https://reviews.llvm.org/D152770
Files:
clang/include/clang/ExtractAPI/API.h
clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
clang/lib/ExtractAPI/API.cpp
clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
clang/test/ExtractAPI/objc_module_category.m
clang/test/ExtractAPI/objc_various_categories.m
Index: clang/test/ExtractAPI/objc_various_categories.m
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/objc_various_categories.m
@@ -0,0 +1,671 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \
+// RUN: %t/reference.output.json.in >> %t/reference.output.json
+// RUN: %clang -extract-api -x objective-c-header \
+// RUN: -target arm64-apple-macosx \
+// RUN: %t/myclass_1.h \
+// RUN: %t/input.h -o %t/output.json | FileCheck -allow-empty %s
+
+// Generator version is not consistent across test runs, normalize it.
+// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
+// RUN: %t/output.json >> %t/output-normalized.json
+// RUN: diff %t/reference.output.json %t/output-normalized.json
+
+// CHECK-NOT: error:
+// CHECK-NOT: warning:
+
+//--- input.h
+#import <Foundation/Foundation.h>
+#import "myclass_1.h"
+#import "myclass_2.h"
+
+@interface MyClass1 (MyCategory1)
+- (int) SomeMethod;
+@end
+
+@interface MyClass2 (MyCategory2)
+- (int) SomeMethod2;
+@end
+
+@interface NSString (Category1)
+-(void) StringMethod;
+@end
+
+@interface NSString (Category2)
+-(void) StringMethod2;
+@end
+
+//--- myclass_1.h
+@interface MyClass1
+@end
+
+//--- myclass_2.h
+@interface MyClass2
+@end
+
+//--- reference.output.json.in
+{
+ "metadata": {
+ "formatVersion": {
+ "major": 0,
+ "minor": 5,
+ "patch": 3
+ },
+ "generator": "?"
+ },
+ "module": {
+ "name": "",
+ "platform": {
+ "architecture": "arm64",
+ "operatingSystem": {
+ "minimumVersion": {
+ "major": 11,
+ "minor": 0,
+ "patch": 0
+ },
+ "name": "macosx"
+ },
+ "vendor": "apple"
+ }
+ },
+ "relationships": [
+ {
+ "kind": "memberOf",
+ "source": "c:objc(cs)MyClass1(im)SomeMethod",
+ "target": "c:objc(cs)MyClass1",
+ "targetFallback": "MyClass1"
+ },
+ {
+ "kind": "memberOf",
+ "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(cy)NSString@Category1",
+ "target": "c:objc(cs)NSString",
+ "targetFallback": "NSString"
+ },
+ {
+ "kind": "memberOf",
+ "source": "c:objc(cs)NSString(im)StringMethod",
+ "target": "c:objc(cy)NSString@Category1",
+ "targetFallback": "Category1"
+ },
+ {
+ "kind": "memberOf",
+ "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": [
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "@interface"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "MyClass1"
+ }
+ ],
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:objc(cs)MyClass1"
+ },
+ "kind": {
+ "displayName": "Class",
+ "identifier": "objective-c.class"
+ },
+ "location": {
+ "position": {
+ "character": 12,
+ "line": 1
+ },
+ "uri": "file://INPUT_DIR/myclass_1.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "MyClass1"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "MyClass1"
+ }
+ ],
+ "title": "MyClass1"
+ },
+ "pathComponents": [
+ "MyClass1"
+ ]
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "text",
+ "spelling": "- ("
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ },
+ {
+ "kind": "text",
+ "spelling": ") "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "SomeMethod"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "functionSignature": {
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:objc(cs)MyClass1(im)SomeMethod"
+ },
+ "kind": {
+ "displayName": "Instance Method",
+ "identifier": "objective-c.method"
+ },
+ "location": {
+ "position": {
+ "character": 1,
+ "line": 6
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "SomeMethod"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "text",
+ "spelling": "- "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "SomeMethod"
+ }
+ ],
+ "title": "SomeMethod"
+ },
+ "pathComponents": [
+ "MyClass1",
+ "SomeMethod"
+ ]
+ },
+ {
+ "accessLevel": "public",
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:objc(cs)MyClass2"
+ },
+ "kind": {
+ "displayName": "Module Extension",
+ "identifier": "objective-c.module.extension"
+ }
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "keyword",
+ "spelling": "@interface"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:objc(cs)MyClass2",
+ "spelling": "MyClass2"
+ },
+ {
+ "kind": "text",
+ "spelling": " ("
+ },
+ {
+ "kind": "identifier",
+ "spelling": "MyCategory2"
+ },
+ {
+ "kind": "text",
+ "spelling": ")"
+ }
+ ],
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:objc(cs)MyClass2"
+ },
+ "kind": {
+ "displayName": "Class Extension",
+ "identifier": "objective-c.class.extension"
+ },
+ "location": {
+ "position": {
+ "character": 12,
+ "line": 9
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "MyCategory2"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "MyCategory2"
+ }
+ ],
+ "title": "MyClass2 (MyCategory2)"
+ },
+ "pathComponents": [
+ "MyCategory2"
+ ]
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "text",
+ "spelling": "- ("
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ },
+ {
+ "kind": "text",
+ "spelling": ") "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "SomeMethod2"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "functionSignature": {
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:I",
+ "spelling": "int"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:objc(cs)MyClass2(im)SomeMethod2"
+ },
+ "kind": {
+ "displayName": "Instance Method",
+ "identifier": "objective-c.method"
+ },
+ "location": {
+ "position": {
+ "character": 1,
+ "line": 10
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "SomeMethod2"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "text",
+ "spelling": "- "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "SomeMethod2"
+ }
+ ],
+ "title": "SomeMethod2"
+ },
+ "pathComponents": [
+ "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": [
+ {
+ "kind": "keyword",
+ "spelling": "@interface"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:objc(cs)NSString",
+ "spelling": "NSString"
+ },
+ {
+ "kind": "text",
+ "spelling": " ("
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Category1"
+ },
+ {
+ "kind": "text",
+ "spelling": ")"
+ }
+ ],
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:objc(cs)NSString"
+ },
+ "kind": {
+ "displayName": "Class Extension",
+ "identifier": "objective-c.class.extension"
+ },
+ "location": {
+ "position": {
+ "character": 12,
+ "line": 13
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "Category1"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Category1"
+ }
+ ],
+ "title": "NSString (Category1)"
+ },
+ "pathComponents": [
+ "Category1"
+ ]
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "text",
+ "spelling": "- ("
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ },
+ {
+ "kind": "text",
+ "spelling": ") "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "StringMethod"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "functionSignature": {
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:objc(cs)NSString(im)StringMethod"
+ },
+ "kind": {
+ "displayName": "Instance Method",
+ "identifier": "objective-c.method"
+ },
+ "location": {
+ "position": {
+ "character": 1,
+ "line": 14
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "StringMethod"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "text",
+ "spelling": "- "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "StringMethod"
+ }
+ ],
+ "title": "StringMethod"
+ },
+ "pathComponents": [
+ "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)NSString"
+ },
+ "kind": {
+ "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(im)StringMethod2"
+ },
+ "kind": {
+ "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"
+ ]
+ }
+ ]
+}
Index: clang/test/ExtractAPI/objc_module_category.m
===================================================================
--- /dev/null
+++ clang/test/ExtractAPI/objc_module_category.m
@@ -0,0 +1,399 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}@g" \
+// RUN: %t/reference.output.json.in >> %t/reference.output.json
+// RUN: %clang -extract-api -x objective-c-header \
+// RUN: -target arm64-apple-macosx \
+// RUN: %t/input.h -o %t/output.json | FileCheck -allow-empty %s
+
+// Generator version is not consistent across test runs, normalize it.
+// RUN: sed -e "s@\"generator\": \".*\"@\"generator\": \"?\"@g" \
+// RUN: %t/output.json >> %t/output-normalized.json
+// RUN: diff %t/reference.output.json %t/output-normalized.json
+
+// CHECK-NOT: error:
+// CHECK-NOT: warning:
+
+//--- input.h
+#import <Foundation/Foundation.h>
+/// Doc comment 1
+@interface NSString (Category1)
+-(void)method1;
+@end
+
+/// Doc comment 2
+@interface NSString (Category2)
+-(void)method2;
+@end
+
+//--- reference.output.json.in
+{
+ "metadata": {
+ "formatVersion": {
+ "major": 0,
+ "minor": 5,
+ "patch": 3
+ },
+ "generator": "?"
+ },
+ "module": {
+ "name": "",
+ "platform": {
+ "architecture": "arm64",
+ "operatingSystem": {
+ "minimumVersion": {
+ "major": 11,
+ "minor": 0,
+ "patch": 0
+ },
+ "name": "macosx"
+ },
+ "vendor": "apple"
+ }
+ },
+ "relationships": [
+ {
+ "kind": "memberOf",
+ "source": "c:objc(cy)NSString@Category1",
+ "target": "c:objc(cs)NSString",
+ "targetFallback": "NSString"
+ },
+ {
+ "kind": "memberOf",
+ "source": "c:objc(cs)NSString(im)method1",
+ "target": "c:objc(cy)NSString@Category1",
+ "targetFallback": "Category1"
+ },
+ {
+ "kind": "memberOf",
+ "source": "c:objc(cy)NSString@Category2",
+ "target": "c:objc(cs)NSString",
+ "targetFallback": "NSString"
+ },
+ {
+ "kind": "memberOf",
+ "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": [
+ {
+ "kind": "keyword",
+ "spelling": "@interface"
+ },
+ {
+ "kind": "text",
+ "spelling": " "
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:objc(cs)NSString",
+ "spelling": "NSString"
+ },
+ {
+ "kind": "text",
+ "spelling": " ("
+ },
+ {
+ "kind": "identifier",
+ "spelling": "Category1"
+ },
+ {
+ "kind": "text",
+ "spelling": ")"
+ }
+ ],
+ "docComment": {
+ "lines": [
+ {
+ "range": {
+ "end": {
+ "character": 18,
+ "line": 2
+ },
+ "start": {
+ "character": 5,
+ "line": 2
+ }
+ },
+ "text": "Doc comment 1"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:objc(cs)NSString"
+ },
+ "kind": {
+ "displayName": "Class Extension",
+ "identifier": "objective-c.class.extension"
+ },
+ "location": {
+ "position": {
+ "character": 12,
+ "line": 3
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "Category1"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "identifier",
+ "spelling": "Category1"
+ }
+ ],
+ "title": "NSString (Category1)"
+ },
+ "pathComponents": [
+ "Category1"
+ ]
+ },
+ {
+ "accessLevel": "public",
+ "declarationFragments": [
+ {
+ "kind": "text",
+ "spelling": "- ("
+ },
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ },
+ {
+ "kind": "text",
+ "spelling": ") "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "method1"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "functionSignature": {
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:objc(cs)NSString(im)method1"
+ },
+ "kind": {
+ "displayName": "Instance Method",
+ "identifier": "objective-c.method"
+ },
+ "location": {
+ "position": {
+ "character": 1,
+ "line": 4
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "method1"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "text",
+ "spelling": "- "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "method1"
+ }
+ ],
+ "title": "method1"
+ },
+ "pathComponents": [
+ "Category1",
+ "method1"
+ ]
+ },
+ {
+ "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": ")"
+ }
+ ],
+ "docComment": {
+ "lines": [
+ {
+ "range": {
+ "end": {
+ "character": 18,
+ "line": 7
+ },
+ "start": {
+ "character": 5,
+ "line": 7
+ }
+ },
+ "text": "Doc comment 2"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:objc(cs)NSString"
+ },
+ "kind": {
+ "displayName": "Class Extension",
+ "identifier": "objective-c.class.extension"
+ },
+ "location": {
+ "position": {
+ "character": 12,
+ "line": 8
+ },
+ "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": "method2"
+ },
+ {
+ "kind": "text",
+ "spelling": ";"
+ }
+ ],
+ "functionSignature": {
+ "returns": [
+ {
+ "kind": "typeIdentifier",
+ "preciseIdentifier": "c:v",
+ "spelling": "void"
+ }
+ ]
+ },
+ "identifier": {
+ "interfaceLanguage": "objective-c",
+ "precise": "c:objc(cs)NSString(im)method2"
+ },
+ "kind": {
+ "displayName": "Instance Method",
+ "identifier": "objective-c.method"
+ },
+ "location": {
+ "position": {
+ "character": 1,
+ "line": 9
+ },
+ "uri": "file://INPUT_DIR/input.h"
+ },
+ "names": {
+ "navigator": [
+ {
+ "kind": "identifier",
+ "spelling": "method2"
+ }
+ ],
+ "subHeading": [
+ {
+ "kind": "text",
+ "spelling": "- "
+ },
+ {
+ "kind": "identifier",
+ "spelling": "method2"
+ }
+ ],
+ "title": "method2"
+ },
+ "pathComponents": [
+ "Category2",
+ "method2"
+ ]
+ }
+ ]
+}
Index: clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
===================================================================
--- clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ 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<const ObjCCategoryRecord>(&Record))
+ Identifier["precise"] = CategoryRecord->Interface.USR;
+ else
+ Identifier["precise"] = Record.USR;
Identifier["interfaceLanguage"] = getLanguageName(Lang);
return Identifier;
@@ -319,7 +323,13 @@
/// Objective-C methods). Can be used as sub-headings for documentation.
Object serializeNames(const APIRecord &Record) {
Object Names;
- Names["title"] = Record.Name;
+ if (auto *CategoryRecord =
+ dyn_cast_or_null<const ObjCCategoryRecord>(&Record))
+ Names["title"] =
+ (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str();
+ else
+ Names["title"] = Record.Name;
+
serializeArray(Names, "subHeading",
serializeDeclarationFragments(Record.SubHeading));
DeclarationFragments NavigatorFragments;
@@ -391,9 +401,12 @@
Kind["displayName"] = "Class";
break;
case APIRecord::RK_ObjCCategory:
- // We don't serialize out standalone Objective-C category symbols yet.
- llvm_unreachable("Serializing standalone Objective-C category symbols is "
- "not supported.");
+ Kind["identifier"] = AddLangPrefix("class.extension");
+ Kind["displayName"] = "Class Extension";
+ break;
+ case APIRecord::RK_ObjCCategoryModule:
+ Kind["identifier"] = AddLangPrefix("module.extension");
+ Kind["displayName"] = "Module Extension";
break;
case APIRecord::RK_ObjCProtocol:
Kind["identifier"] = AddLangPrefix("protocol");
@@ -497,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<ObjCCategoryRecord>(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
@@ -735,6 +750,45 @@
}
}
+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)
+ return;
+
+ Symbols.emplace_back(std::move(*ObjCCategory));
+ serializeMembers(Record, Record.Methods);
+ serializeMembers(Record, Record.Properties);
+
+ // Surface the protocols of the category to the interface.
+ for (const auto &Protocol : Record.Protocols)
+ serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
+}
+
void SymbolGraphSerializer::visitMacroDefinitionRecord(
const MacroDefinitionRecord &Record) {
auto Macro = serializeAPIRecord(Record);
@@ -767,6 +821,9 @@
case APIRecord::RK_ObjCProtocol:
visitObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));
break;
+ case APIRecord::RK_ObjCCategory:
+ visitObjCCategoryRecord(*cast<ObjCCategoryRecord>(Record));
+ break;
case APIRecord::RK_MacroDefinition:
visitMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));
break;
@@ -835,9 +892,6 @@
if (!Record)
return {};
- if (isa<ObjCCategoryRecord>(Record))
- return {};
-
Object Root;
APIIgnoresList EmptyIgnores;
SymbolGraphSerializer Serializer(API, EmptyIgnores,
Index: clang/lib/ExtractAPI/API.cpp
===================================================================
--- clang/lib/ExtractAPI/API.cpp
+++ clang/lib/ExtractAPI/API.cpp
@@ -124,15 +124,16 @@
StringRef Name, StringRef USR, PresumedLoc Loc,
AvailabilitySet Availabilities, const DocComment &Comment,
DeclarationFragments Declaration, DeclarationFragments SubHeading,
- SymbolReference Interface, bool IsFromSystemHeader) {
+ SymbolReference Interface, bool IsFromSystemHeader,
+ bool IsFromExternalModule) {
// Create the category record.
auto *Record =
addTopLevelRecord(USRBasedLookupTable, ObjCCategories, USR, Name, Loc,
std::move(Availabilities), Comment, Declaration,
SubHeading, Interface, IsFromSystemHeader);
- // If this category is extending a known interface, associate it with the
- // ObjCInterfaceRecord.
+ Record->IsFromExternalModule = IsFromExternalModule;
+
auto It = ObjCInterfaces.find(Interface.USR);
if (It != ObjCInterfaces.end())
It->second->Categories.push_back(Record);
Index: clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ 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);
@@ -163,6 +166,9 @@
/// Visit an Objective-C container record.
void visitObjCContainerRecord(const ObjCContainerRecord &Record);
+ /// Visit an Objective-C category record.
+ void visitObjCCategoryRecord(const ObjCCategoryRecord &Record);
+
/// Visit a macro definition record.
void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record);
Index: clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
+++ clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
@@ -35,6 +35,8 @@
getDerived()->traverseObjCProtocols();
+ getDerived()->traverseObjCCategories();
+
getDerived()->traverseMacroDefinitionRecords();
getDerived()->traverseTypedefRecords();
@@ -70,6 +72,11 @@
getDerived()->visitObjCContainerRecord(*Protocol.second);
}
+ void traverseObjCCategories() {
+ for (const auto &Category : API.getObjCCategories())
+ getDerived()->visitObjCCategoryRecord(*Category.second);
+ }
+
void traverseMacroDefinitionRecords() {
for (const auto &Macro : API.getMacros())
getDerived()->visitMacroDefinitionRecord(*Macro.second);
@@ -95,6 +102,9 @@
/// Visit an Objective-C container record.
void visitObjCContainerRecord(const ObjCContainerRecord &Record){};
+ /// Visit an Objective-C category record.
+ void visitObjCCategoryRecord(const ObjCCategoryRecord &Record){};
+
/// Visit a macro definition record.
void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record){};
Index: clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
===================================================================
--- clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -484,9 +484,17 @@
SymbolReference Interface(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,
- Interface, isInSystemHeader(Decl));
+ Interface, isInSystemHeader(Decl), IsFromExternalModule);
getDerivedExtractAPIVisitor().recordObjCMethods(ObjCCategoryRecord,
Decl->methods());
Index: clang/include/clang/ExtractAPI/API.h
===================================================================
--- clang/include/clang/ExtractAPI/API.h
+++ clang/include/clang/ExtractAPI/API.h
@@ -71,6 +71,7 @@
RK_ObjCInstanceMethod,
RK_ObjCInterface,
RK_ObjCCategory,
+ RK_ObjCCategoryModule,
RK_ObjCProtocol,
RK_MacroDefinition,
RK_Typedef,
@@ -144,6 +145,9 @@
Comment(Comment), Declaration(Declaration), SubHeading(SubHeading),
IsFromSystemHeader(IsFromSystemHeader), Kind(Kind) {}
+ APIRecord(RecordKind Kind, StringRef USR, StringRef Name)
+ : USR(USR), Name(Name), Kind(Kind) {}
+
// Pure virtual destructor to make APIRecord abstract
virtual ~APIRecord() = 0;
};
@@ -468,6 +472,8 @@
/// This holds information associated with Objective-C categories.
struct ObjCCategoryRecord : ObjCContainerRecord {
SymbolReference Interface;
+ /// Determine whether the Category is derived from external class interface.
+ bool IsFromExternalModule = false;
ObjCCategoryRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
AvailabilitySet Availabilities, const DocComment &Comment,
@@ -679,7 +685,7 @@
AvailabilitySet Availability, const DocComment &Comment,
DeclarationFragments Declaration,
DeclarationFragments SubHeading, SymbolReference Interface,
- bool IsFromSystemHeader);
+ bool IsFromSystemHeader, bool IsFromExternalModule);
/// Create and add an Objective-C interface record into the API set.
///
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits