mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-13 19:24:21 +00:00
[clang][ExtractAPI] Add support for Objective-C categories
Differential Revision: https://reviews.llvm.org/D152770
This commit is contained in:
parent
b0a77af4f1
commit
1849318539
@ -80,6 +80,7 @@ struct APIRecord {
|
||||
RK_ObjCInstanceMethod,
|
||||
RK_ObjCInterface,
|
||||
RK_ObjCCategory,
|
||||
RK_ObjCCategoryModule,
|
||||
RK_ObjCProtocol,
|
||||
RK_MacroDefinition,
|
||||
RK_Typedef,
|
||||
@ -153,6 +154,9 @@ public:
|
||||
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;
|
||||
};
|
||||
@ -643,6 +647,8 @@ private:
|
||||
/// 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,
|
||||
@ -895,7 +901,7 @@ public:
|
||||
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.
|
||||
///
|
||||
|
@ -578,9 +578,17 @@ bool ExtractAPIVisitorBase<Derived>::VisitObjCCategoryDecl(
|
||||
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());
|
||||
|
@ -39,6 +39,8 @@ public:
|
||||
|
||||
getDerived()->traverseObjCProtocols();
|
||||
|
||||
getDerived()->traverseObjCCategories();
|
||||
|
||||
getDerived()->traverseMacroDefinitionRecords();
|
||||
|
||||
getDerived()->traverseTypedefRecords();
|
||||
@ -84,6 +86,11 @@ public:
|
||||
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);
|
||||
@ -113,6 +120,9 @@ public:
|
||||
/// 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){};
|
||||
|
||||
|
@ -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"
|
||||
@ -87,6 +88,10 @@ public:
|
||||
/// The source symbol conforms to the target symbol.
|
||||
/// For example Objective-C protocol conformances.
|
||||
ConformsTo,
|
||||
|
||||
/// The source symbol is an extension to the target symbol.
|
||||
/// For example Objective-C categories extending an external type.
|
||||
ExtensionTo,
|
||||
};
|
||||
|
||||
/// Get the string representation of the relationship kind.
|
||||
@ -147,6 +152,8 @@ protected:
|
||||
|
||||
SymbolGraphSerializerOption Options;
|
||||
|
||||
llvm::StringSet<> visitedCategories;
|
||||
|
||||
public:
|
||||
/// Visit a global function record.
|
||||
void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record);
|
||||
@ -167,6 +174,9 @@ public:
|
||||
/// 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);
|
||||
|
||||
|
@ -209,15 +209,16 @@ ObjCCategoryRecord *APISet::addObjCCategory(
|
||||
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);
|
||||
|
@ -328,7 +328,13 @@ serializeDeclarationFragments(const DeclarationFragments &DF) {
|
||||
/// 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;
|
||||
@ -432,9 +438,12 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
|
||||
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");
|
||||
@ -563,14 +572,16 @@ bool generatePathComponents(
|
||||
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
|
||||
@ -709,6 +720,8 @@ StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
|
||||
return "inheritsFrom";
|
||||
case RelationshipKind::ConformsTo:
|
||||
return "conformsTo";
|
||||
case RelationshipKind::ExtensionTo:
|
||||
return "extensionTo";
|
||||
}
|
||||
llvm_unreachable("Unhandled relationship kind");
|
||||
}
|
||||
@ -820,6 +833,45 @@ void SymbolGraphSerializer::visitObjCContainerRecord(
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolGraphSerializer::visitObjCCategoryRecord(
|
||||
const ObjCCategoryRecord &Record) {
|
||||
if (!Record.IsFromExternalModule)
|
||||
return;
|
||||
|
||||
// Check if the current Category' parent has been visited before, if so skip.
|
||||
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::ExtensionTo);
|
||||
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);
|
||||
@ -858,6 +910,9 @@ void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
|
||||
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;
|
||||
@ -926,9 +981,6 @@ SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
|
||||
if (!Record)
|
||||
return {};
|
||||
|
||||
if (isa<ObjCCategoryRecord>(Record))
|
||||
return {};
|
||||
|
||||
Object Root;
|
||||
APIIgnoresList EmptyIgnores;
|
||||
SymbolGraphSerializer Serializer(API, EmptyIgnores,
|
||||
|
404
clang/test/ExtractAPI/objc_module_category.m
Normal file
404
clang/test/ExtractAPI/objc_module_category.m
Normal file
@ -0,0 +1,404 @@
|
||||
// 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.h"
|
||||
|
||||
/// Doc comment 1
|
||||
@interface NSString (Category1)
|
||||
-(void)method1;
|
||||
@end
|
||||
|
||||
/// Doc comment 2
|
||||
@interface NSString (Category2)
|
||||
-(void)method2;
|
||||
@end
|
||||
|
||||
//--- Foundation.h
|
||||
@interface NSString
|
||||
@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": "extensionTo",
|
||||
"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": "extensionTo",
|
||||
"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(cy)NSString@Category1"
|
||||
},
|
||||
"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": 3
|
||||
},
|
||||
"start": {
|
||||
"character": 5,
|
||||
"line": 3
|
||||
}
|
||||
},
|
||||
"text": "Doc comment 1"
|
||||
}
|
||||
]
|
||||
},
|
||||
"identifier": {
|
||||
"interfaceLanguage": "objective-c",
|
||||
"precise": "c:objc(cy)NSString@Category1"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Class Extension",
|
||||
"identifier": "objective-c.class.extension"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 12,
|
||||
"line": 4
|
||||
},
|
||||
"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": 5
|
||||
},
|
||||
"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": 8
|
||||
},
|
||||
"start": {
|
||||
"character": 5,
|
||||
"line": 8
|
||||
}
|
||||
},
|
||||
"text": "Doc comment 2"
|
||||
}
|
||||
]
|
||||
},
|
||||
"identifier": {
|
||||
"interfaceLanguage": "objective-c",
|
||||
"precise": "c:objc(cy)NSString@Category2"
|
||||
},
|
||||
"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": "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": 10
|
||||
},
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
507
clang/test/ExtractAPI/objc_various_categories.m
Normal file
507
clang/test/ExtractAPI/objc_various_categories.m
Normal file
@ -0,0 +1,507 @@
|
||||
// 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 "myclass_1.h"
|
||||
#import "Foundation.h"
|
||||
|
||||
@interface MyClass1 (MyCategory1)
|
||||
- (int) SomeMethod;
|
||||
@end
|
||||
|
||||
@interface NSString (Category1)
|
||||
-(void) StringMethod;
|
||||
@end
|
||||
|
||||
@interface NSString (Category2)
|
||||
-(void) StringMethod2;
|
||||
@end
|
||||
|
||||
//--- myclass_1.h
|
||||
@interface MyClass1
|
||||
@end
|
||||
|
||||
//--- Foundation.h
|
||||
@interface NSString
|
||||
@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": "extensionTo",
|
||||
"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": "extensionTo",
|
||||
"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": 5
|
||||
},
|
||||
"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(cy)NSString@Category1"
|
||||
},
|
||||
"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(cy)NSString@Category1"
|
||||
},
|
||||
"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": "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": 9
|
||||
},
|
||||
"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(cy)NSString@Category2"
|
||||
},
|
||||
"kind": {
|
||||
"displayName": "Class Extension",
|
||||
"identifier": "objective-c.class.extension"
|
||||
},
|
||||
"location": {
|
||||
"position": {
|
||||
"character": 12,
|
||||
"line": 12
|
||||
},
|
||||
"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": 13
|
||||
},
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user