Skip to content

Commit 8e7ea0c

Browse files
committed
[apinotes] Add support for nested tags and namespaces.
1 parent 07b7fc9 commit 8e7ea0c

File tree

4 files changed

+105
-58
lines changed

4 files changed

+105
-58
lines changed

clang/lib/Sema/SemaAPINotes.cpp

Lines changed: 69 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -867,45 +867,6 @@ void Sema::ProcessAPINotes(Decl *D) {
867867
return;
868868
}
869869

870-
// Tags
871-
if (auto Tag = dyn_cast<TagDecl>(D)) {
872-
std::string LookupName = Tag->getName().str();
873-
874-
// Use the source location to discern if this Tag is an OPTIONS macro.
875-
// For now we would like to limit this trick of looking up the APINote tag
876-
// using the EnumDecl's QualType in the case where the enum is anonymous.
877-
// This is only being used to support APINotes lookup for C++ NS/CF_OPTIONS
878-
// when C++-Interop is enabled.
879-
std::string MacroName =
880-
LookupName.empty() && Tag->getOuterLocStart().isMacroID()
881-
? clang::Lexer::getImmediateMacroName(
882-
Tag->getOuterLocStart(),
883-
Tag->getASTContext().getSourceManager(), LangOpts)
884-
.str()
885-
: "";
886-
887-
if (LookupName.empty() && isa<clang::EnumDecl>(Tag) &&
888-
(MacroName == "CF_OPTIONS" || MacroName == "NS_OPTIONS" ||
889-
MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS")) {
890-
891-
clang::QualType T = llvm::cast<clang::EnumDecl>(Tag)->getIntegerType();
892-
LookupName = clang::QualType::getAsString(
893-
T.split(), getASTContext().getPrintingPolicy());
894-
}
895-
896-
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
897-
auto Info = Reader->lookupTag(LookupName);
898-
ProcessVersionedAPINotes(*this, Tag, Info);
899-
}
900-
901-
for (auto Member : Tag->decls()) {
902-
if (isa<CXXMethodDecl>(Member))
903-
ProcessAPINotes(Member);
904-
}
905-
906-
return;
907-
}
908-
909870
// Typedefs
910871
if (auto Typedef = dyn_cast<TypedefNameDecl>(D)) {
911872
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
@@ -917,22 +878,84 @@ void Sema::ProcessAPINotes(Decl *D) {
917878
}
918879
}
919880

881+
// Tags
882+
if (auto Tag = dyn_cast<TagDecl>(D)) {
883+
std::string LookupName = Tag->getName().str();
884+
885+
auto parent = Tag->getParent();
886+
while (isa<clang::CXXRecordDecl>(parent) ||
887+
isa<clang::NamespaceDecl>(parent)) {
888+
if (auto Record = dyn_cast<clang::CXXRecordDecl>(parent)) {
889+
LookupName = Record->getNameAsString() + "." + LookupName;
890+
} else if (auto Namespace = dyn_cast<clang::NamespaceDecl>(parent)) {
891+
LookupName = Namespace->getNameAsString() + "." + LookupName;
892+
}
893+
894+
parent = parent->getParent();
895+
}
896+
897+
// Use the source location to discern if this Tag is an OPTIONS macro.
898+
// For now we would like to limit this trick of looking up the APINote tag
899+
// using the EnumDecl's QualType in the case where the enum is anonymous.
900+
// This is only being used to support APINotes lookup for C++ NS/CF_OPTIONS
901+
// when C++-Interop is enabled.
902+
std::string MacroName =
903+
LookupName.empty() && Tag->getOuterLocStart().isMacroID()
904+
? clang::Lexer::getImmediateMacroName(
905+
Tag->getOuterLocStart(),
906+
Tag->getASTContext().getSourceManager(), LangOpts)
907+
.str()
908+
: "";
909+
910+
if (LookupName.empty() && isa<clang::EnumDecl>(Tag) &&
911+
(MacroName == "CF_OPTIONS" || MacroName == "NS_OPTIONS" ||
912+
MacroName == "OBJC_OPTIONS" || MacroName == "SWIFT_OPTIONS")) {
913+
914+
clang::QualType T = llvm::cast<clang::EnumDecl>(Tag)->getIntegerType();
915+
LookupName = clang::QualType::getAsString(
916+
T.split(), getASTContext().getPrintingPolicy());
917+
}
918+
919+
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
920+
auto Info = Reader->lookupTag(LookupName);
921+
ProcessVersionedAPINotes(*this, Tag, Info);
922+
}
923+
924+
for (auto Member : Tag->decls()) {
925+
ProcessAPINotes(Member);
926+
}
927+
928+
return;
929+
}
930+
920931
if (auto Method = dyn_cast<CXXMethodDecl>(D)) {
921932
for (auto Reader : APINotes.findAPINotes(D->getLocation())) {
922933
auto Name = Method->getNameAsString();
923-
auto parent = Method->getParent();
924-
std::string parents = parent->getNameAsString();
925-
while (isa<clang::CXXRecordDecl>(parent->getParent())) {
926-
parent = cast<clang::CXXRecordDecl>(parent->getParent());
927-
parents += "." + parent->getNameAsString();
934+
const clang::DeclContext *parent = Method->getParent();
935+
while (isa<clang::CXXRecordDecl>(parent) ||
936+
isa<clang::NamespaceDecl>(parent)) {
937+
if (auto Record = dyn_cast<clang::CXXRecordDecl>(parent)) {
938+
Name = Record->getNameAsString() + "." + Name;
939+
} else if (auto Namespace = dyn_cast<clang::NamespaceDecl>(parent)) {
940+
Name = Namespace->getNameAsString() + "." + Name;
941+
}
942+
943+
parent = parent->getParent();
928944
}
929945

930-
auto FullName = parents + "." + Name;
931-
auto Info = Reader->lookupMemberFunction(FullName);
946+
auto Info = Reader->lookupMemberFunction(Name);
932947
ProcessVersionedAPINotes(*this, Method, Info);
933948
}
934949
}
935950

951+
if (auto Namespace = dyn_cast<NamespaceDecl>(D)) {
952+
for (auto Redecl : Namespace->redecls()) {
953+
for (auto Member : Redecl->decls()) {
954+
ProcessAPINotes(Member);
955+
}
956+
}
957+
}
958+
936959
// Enumerators.
937960
if (D->getDeclContext()->getRedeclContext()->isFileContext() ||
938961
D->getDeclContext()->getRedeclContext()->isExternCContext()) {

clang/test/APINotes/Inputs/Frameworks/CXXInteropKit.framework/Headers/CXXInteropKit.apinotes

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@ Enumerators:
1313
Tags:
1414
- Name: NSSomeEnumOptions
1515
SwiftName: SomeEnum.Options
16-
- Name: Struct
17-
SwiftName: SwiftStruct
16+
- Name: GlobalStruct
1817
Methods:
1918
- Name: 'method'
20-
SwiftName: swiftMethod()
19+
SwiftName: globalMethod()
20+
- Name: ParentNS.ChildNS.ParentStruct.ChildStruct
21+
Methods:
22+
- Name: 'method'
23+
SwiftName: nestedMethod()

clang/test/APINotes/Inputs/Frameworks/CXXInteropKit.framework/Headers/CXXInteropKit.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,21 @@ typedef NS_OPTIONS(NSUInteger, NSSomeEnumOptions) {
2222
NSSomeEnumWithBlue,
2323
};
2424

25-
struct Struct {
25+
struct GlobalStruct {
26+
int x;
2627
void method() {}
27-
};
28+
};
29+
30+
namespace ParentNS {
31+
namespace ChildNS {
32+
33+
struct ParentStruct {
34+
int x;
35+
struct ChildStruct {
36+
int y;
37+
void method() {}
38+
};
39+
};
40+
41+
}
42+
}

clang/test/APINotes/objcxx-swift-name.m

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
11
// RUN: rm -rf %t && mkdir -p %t
22
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/CxxInterop -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -x objective-c++
33
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/CxxInterop -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter SomeClass -x objective-c++ | FileCheck %s
4+
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/CxxInterop -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter method -x objective-c++ | FileCheck -check-prefix=CHECK-METHOD %s
45
// RUN: %clang_cc1 -fmodules -fblocks -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache/CxxInterop -fdisable-module-hash -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -ast-dump -ast-dump-filter "(anonymous)" -x objective-c++ | FileCheck -check-prefix=CHECK-ANONYMOUS-ENUM %s
56

67
#import <CXXInteropKit/CXXInteropKit.h>
78

89
// CHECK: Dumping NSSomeClass:
9-
// CHECK-NEXT: ObjCInterfaceDecl {{.+}} imported in CXXInteropKit <undeserialized declarations> NSSomeClass
10-
// CHECK-NEXT: SwiftNameAttr {{.+}} <<invalid sloc>> "SomeClass"
10+
// CHECK: ObjCInterfaceDecl {{.+}} imported in CxxInteropKit <undeserialized declarations> NSSomeClass
11+
// CHECK: SwiftNameAttr {{.+}} <<invalid sloc>> "SomeClass"
1112

1213
// CHECK: Dumping NSSomeClass::didMoveToParentViewController::
13-
// CHECK-NEXT: ObjCMethodDecl {{.+}} imported in CXXInteropKit - didMoveToParentViewController: 'void'
14-
// CHECK-NEXT: ParmVarDecl
15-
// CHECK-NEXT: SwiftNameAttr {{.+}} <<invalid sloc>> "didMove(toParent:)"
14+
// CHECK: ObjCMethodDecl {{.+}} imported in CxxInteropKit - didMoveToParentViewController: 'void'
15+
// CHECK: SwiftNameAttr {{.+}} <<invalid sloc>> "didMove(toParent:)"
1616

1717
// CHECK: Dumping SomeClassRed:
18-
// CHECK-NEXT: EnumConstantDecl {{.+}} imported in CXXInteropKit SomeClassRed 'ColorEnum'
19-
// CHECK-NEXT: SwiftNameAttr {{.+}} <<invalid sloc>> "red"
18+
// CHECK: EnumConstantDecl {{.+}} imported in CxxInteropKit SomeClassRed 'ColorEnum'
19+
// CHECK: SwiftNameAttr {{.+}} <<invalid sloc>> "red"
20+
21+
// CHECK-METHOD: Dumping GlobalStruct::method:
22+
// CHECK-METHOD: SwiftNameAttr {{.+}} <<invalid sloc>> "globalMethod()"
23+
24+
// CHECK-METHOD: Dumping ParentNS::ChildNS::ParentStruct::ChildStruct::method:
25+
// CHECK-METHOD: SwiftNameAttr {{.+}} <<invalid sloc>> "nestedMethod()"
2026

2127
// CHECK-ANONYMOUS-ENUM: Dumping (anonymous):
2228
// CHECK-ANONYMOUS-ENUM-NEXT: EnumDecl {{.+}} imported in CXXInteropKit <undeserialized declarations> 'NSSomeEnumOptions':'unsigned long'

0 commit comments

Comments
 (0)