Skip to content

Commit a4ea927

Browse files
committed
[ClangImporter] If a protocol and a class have the same name, add "Protocol".
.../if/ the protocol and the class are from the same top-level Clang module. If not, the protocol is /not/ renamed, and users will have to disambiguate with module qualification. This kills our hardcoded "RenamedProtocols" list; it turns out this pattern is more common than we thought /and/ leads to cross-referencing issues. <rdar://problem/16206627> Swift SVN r18809
1 parent 8548760 commit a4ea927

File tree

11 files changed

+182
-128
lines changed

11 files changed

+182
-128
lines changed

include/swift/Basic/LLVM.h

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace llvm {
2929
template <typename T, unsigned N> class SmallPtrSet;
3030
template <typename T> class SmallVectorImpl;
3131
template <typename T, unsigned N> class SmallVector;
32+
template <unsigned N> class SmallString;
3233
template<typename T> class ArrayRef;
3334
template<typename T> class MutableArrayRef;
3435
template<typename T> class TinyPtrVector;
@@ -52,6 +53,7 @@ namespace swift {
5253
// Containers
5354
using llvm::SmallPtrSetImpl;
5455
using llvm::SmallPtrSet;
56+
using llvm::SmallString;
5557
using llvm::StringRef;
5658
using llvm::Twine;
5759
using llvm::SmallVectorImpl;

include/swift/ClangImporter/RenamedProtocols.def

-24
This file was deleted.

lib/ClangImporter/ClangImporter.cpp

+38-52
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,10 @@ ClangImporter::Implementation::getClangSubmoduleForDecl(
554554
actual = TD->getDefinition();
555555
if (!actual && !allowForwardDeclaration)
556556
return Nothing;
557+
} else if (auto OPD = dyn_cast<clang::ObjCProtocolDecl>(D)) {
558+
actual = OPD->getDefinition();
559+
if (!actual && !allowForwardDeclaration)
560+
return Nothing;
557561
}
558562

559563
if (!actual)
@@ -1224,22 +1228,6 @@ void ClangImporter::lookupValue(Identifier name, VisibleDeclConsumer &consumer){
12241228
auto &pp = Impl.Instance->getPreprocessor();
12251229
auto &sema = Impl.Instance->getSema();
12261230

1227-
// If the given name matches one of a special set of renamed
1228-
// protocol names, perform protocol lookup. For example, the
1229-
// NSObject protocol is named NSObjectProto so that it does not
1230-
// conflict with the NSObject class.
1231-
// FIXME: It would be better to put protocols into a submodule, so
1232-
// that normal name lookup would prefer the class (NSObject) but
1233-
// protocols would be visible with, e.g., protocols.NSObject.
1234-
auto lookupNameKind = clang::Sema::LookupOrdinaryName;
1235-
if (false) { }
1236-
#define RENAMED_PROTOCOL(ObjCName, SwiftName) \
1237-
else if (name.str().equals(#SwiftName)) { \
1238-
name = Impl.SwiftContext.getIdentifier(#ObjCName); \
1239-
lookupNameKind = clang::Sema::LookupObjCProtocolName; \
1240-
}
1241-
#include "swift/ClangImporter/RenamedProtocols.def"
1242-
12431231
// Map the name. If we can't represent the Swift name in Clang, bail out now.
12441232
auto clangName = Impl.importName(name);
12451233
if (!clangName)
@@ -1255,73 +1243,71 @@ void ClangImporter::lookupValue(Identifier name, VisibleDeclConsumer &consumer){
12551243
}
12561244
}
12571245

1258-
// Perform name lookup into the global scope.
1259-
// FIXME: Map source locations over.
1260-
clang::LookupResult lookupResult(sema, clangName, clang::SourceLocation(),
1261-
lookupNameKind);
12621246
bool FoundType = false;
12631247
bool FoundAny = false;
1264-
if (sema.LookupName(lookupResult, /*Scope=*/0)) {
1248+
auto processResults = [&](clang::LookupResult &result) {
12651249
// FIXME: Filter based on access path? C++ access control?
1266-
for (auto decl : lookupResult) {
1267-
if (auto swiftDecl = Impl.importDeclReal(decl->getUnderlyingDecl()))
1250+
for (auto decl : result) {
1251+
if (auto swiftDecl = Impl.importDeclReal(decl->getUnderlyingDecl())) {
12681252
if (auto valueDecl = dyn_cast<ValueDecl>(swiftDecl)) {
12691253
// If the importer gave us a declaration from the stdlib, make sure
12701254
// it does not show up in the lookup results for the imported module.
12711255
if (valueDecl->getDeclContext()->isModuleScopeContext() &&
12721256
valueDecl->getModuleContext() == Impl.getStdlibModule())
12731257
continue;
1258+
// Check that we didn't pick up something with a remapped name.
1259+
if (valueDecl->getName() != name)
1260+
continue;
12741261

12751262
consumer.foundDecl(valueDecl, DeclVisibilityKind::VisibleAtTopLevel);
12761263
FoundType = FoundType || isa<TypeDecl>(valueDecl);
12771264
FoundAny = true;
12781265
}
1266+
}
12791267
}
1280-
}
1268+
};
1269+
1270+
// Perform name lookup into the global scope.
1271+
// FIXME: Map source locations over.
1272+
clang::LookupResult lookupResult(sema, clangName, clang::SourceLocation(),
1273+
clang::Sema::LookupOrdinaryName);
1274+
if (sema.LookupName(lookupResult, /*Scope=*/nullptr))
1275+
processResults(lookupResult);
12811276

1282-
if (lookupNameKind == clang::Sema::LookupOrdinaryName && !FoundType) {
1277+
if (!FoundType) {
12831278
// Look up a tag name if we did not find a type with this name already.
12841279
// We don't want to introduce multiple types with same name.
12851280
lookupResult.clear(clang::Sema::LookupTagName);
1286-
if (sema.LookupName(lookupResult, /*Scope=*/0)) {
1287-
// FIXME: Filter based on access path? C++ access control?
1288-
for (auto decl : lookupResult) {
1289-
if (auto swiftDecl = Impl.importDeclReal(decl->getUnderlyingDecl()))
1290-
if (auto valueDecl = dyn_cast<ValueDecl>(swiftDecl)) {
1291-
consumer.foundDecl(valueDecl, DeclVisibilityKind::VisibleAtTopLevel);
1292-
FoundAny = true;
1293-
}
1294-
}
1295-
}
1281+
if (sema.LookupName(lookupResult, /*Scope=*/nullptr))
1282+
processResults(lookupResult);
12961283
}
12971284

1298-
if (lookupNameKind == clang::Sema::LookupOrdinaryName && !FoundAny) {
1299-
// Look up a protocol name if we did not find anything with this
1300-
// name already.
1285+
// Look up protocol names as well.
1286+
lookupResult.clear(clang::Sema::LookupObjCProtocolName);
1287+
if (sema.LookupName(lookupResult, /*Scope=*/nullptr)) {
1288+
processResults(lookupResult);
1289+
1290+
} else if (!FoundAny && name.str().endswith(SWIFT_PROTOCOL_SUFFIX)) {
1291+
auto noProtoNameStr = name.str().drop_back(strlen(SWIFT_PROTOCOL_SUFFIX));
1292+
auto protoIdent = &Impl.getClangASTContext().Idents.get(noProtoNameStr);
13011293
lookupResult.clear(clang::Sema::LookupObjCProtocolName);
1302-
if (sema.LookupName(lookupResult, /*Scope=*/0)) {
1303-
// FIXME: Filter based on access path? C++ access control?
1304-
for (auto decl : lookupResult) {
1305-
if (auto swiftDecl = Impl.importDeclReal(decl->getUnderlyingDecl())) {
1306-
if (auto valueDecl = dyn_cast<ValueDecl>(swiftDecl)) {
1307-
consumer.foundDecl(valueDecl, DeclVisibilityKind::VisibleAtTopLevel);
1308-
FoundAny = true;
1309-
}
1310-
}
1311-
}
1312-
}
1294+
lookupResult.setLookupName(protoIdent);
1295+
1296+
if (sema.LookupName(lookupResult, /*Scope=*/nullptr))
1297+
processResults(lookupResult);
1298+
1299+
lookupResult.setLookupName(clangName);
13131300
}
13141301

13151302
// If we *still* haven't found anything, try looking for '<name>Ref'.
13161303
// Eventually, this should be optimized by recognizing this case when
13171304
// generating the clang module.
1318-
if (lookupNameKind == clang::Sema::LookupOrdinaryName &&
1319-
!FoundAny && clangID && Impl.SwiftContext.LangOpts.ImportCFTypes) {
1305+
if (!FoundAny && clangID && Impl.SwiftContext.LangOpts.ImportCFTypes) {
13201306
lookupResult.clear(clang::Sema::LookupOrdinaryName);
13211307

13221308
llvm::SmallString<128> buffer;
13231309
buffer += clangID->getName();
1324-
buffer += "Ref";
1310+
buffer += SWIFT_CFTYPE_SUFFIX;
13251311
auto refIdent = &Impl.Instance->getASTContext().Idents.get(buffer.str());
13261312
lookupResult.setLookupName(refIdent);
13271313

lib/ClangImporter/ImportDecl.cpp

+54-18
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "clang/AST/DeclVisitor.h"
3333
#include "clang/Basic/CharInfo.h"
3434
#include "clang/Lex/Preprocessor.h"
35+
#include "clang/Sema/Lookup.h"
3536

3637
#include "llvm/ADT/SmallString.h"
3738
#include "llvm/ADT/Statistic.h"
@@ -986,7 +987,7 @@ namespace {
986987
theClass->setCheckedInheritanceClause();
987988
theClass->setAddedImplicitInitializers(); // suppress all initializers
988989
theClass->setForeign(true);
989-
addObjCAttribute(theClass, ObjCSelector(Impl.SwiftContext, 0, className));
990+
addObjCAttribute(theClass, className);
990991
Impl.registerExternalDecl(theClass);
991992

992993
SmallVector<ProtocolDecl *, 4> protocols;
@@ -1028,7 +1029,7 @@ namespace {
10281029

10291030
// Import 'typedef struct __Blah *BlahRef;' as a CF type.
10301031
if (!SwiftType && Impl.SwiftContext.LangOpts.ImportCFTypes &&
1031-
Decl->getName().endswith("Ref")) {
1032+
Decl->getName().endswith(SWIFT_CFTYPE_SUFFIX)) {
10321033
if (auto pointee = CFPointeeInfo::classifyTypedef(Decl)) {
10331034
// If the pointee is a record, consider creating a class type.
10341035
if (pointee.isRecord()) {
@@ -1960,6 +1961,14 @@ namespace {
19601961
}
19611962
}
19621963

1964+
/// Add an @objc(name) attribute with the given, optional name expressed as
1965+
/// selector.
1966+
///
1967+
/// The importer should use this rather than adding the attribute directly.
1968+
void addObjCAttribute(ValueDecl *decl, Identifier name) {
1969+
addObjCAttribute(decl, ObjCSelector(Impl.SwiftContext, 0, name));
1970+
}
1971+
19631972
Decl *VisitObjCMethodDecl(const clang::ObjCMethodDecl *decl) {
19641973
auto dc = Impl.importDeclContextOf(decl);
19651974
if (!dc)
@@ -3812,19 +3821,8 @@ namespace {
38123821
}
38133822

38143823
Decl *VisitObjCProtocolDecl(const clang::ObjCProtocolDecl *decl) {
3815-
// Form the protocol name, using the renaming table when necessary.
3816-
Identifier name;
3817-
Identifier origName = Impl.importName(decl->getDeclName());
3818-
if (false) { }
3819-
#define RENAMED_PROTOCOL(ObjCName, SwiftName) \
3820-
else if (decl->getName().equals(#ObjCName)) { \
3821-
name = Impl.SwiftContext.getIdentifier(#SwiftName); \
3822-
}
3823-
#include "swift/ClangImporter/RenamedProtocols.def"
3824-
else {
3825-
name = origName;
3826-
}
3827-
3824+
clang::DeclarationName clangName = decl->getDeclName();
3825+
Identifier name = Impl.importName(clangName);
38283826
if (name.empty())
38293827
return nullptr;
38303828

@@ -3843,6 +3841,44 @@ namespace {
38433841

38443842
decl = decl->getDefinition();
38453843

3844+
// Test to see if there is a value with the same name as the protocol
3845+
// in the same module.
3846+
// FIXME: This will miss macros.
3847+
auto clangModule = Impl.getClangSubmoduleForDecl(decl);
3848+
if (clangModule.hasValue() && clangModule.getValue())
3849+
clangModule = clangModule.getValue()->getTopLevelModule();
3850+
3851+
auto isInSameModule = [&](const clang::Decl *D) -> bool {
3852+
auto declModule = Impl.getClangSubmoduleForDecl(D);
3853+
if (!declModule.hasValue())
3854+
return false;
3855+
return *clangModule == declModule.getValue()->getTopLevelModule();
3856+
};
3857+
3858+
3859+
bool hasConflict = false;
3860+
clang::LookupResult lookupResult(Impl.getClangSema(), clangName,
3861+
clang::SourceLocation(),
3862+
clang::Sema::LookupOrdinaryName);
3863+
if (Impl.getClangSema().LookupName(lookupResult, /*scope=*/nullptr)) {
3864+
hasConflict = std::any_of(lookupResult.begin(), lookupResult.end(),
3865+
isInSameModule);
3866+
}
3867+
if (!hasConflict) {
3868+
lookupResult.clear(clang::Sema::LookupTagName);
3869+
if (Impl.getClangSema().LookupName(lookupResult, /*scope=*/nullptr)) {
3870+
hasConflict = std::any_of(lookupResult.begin(), lookupResult.end(),
3871+
isInSameModule);
3872+
}
3873+
}
3874+
3875+
Identifier origName = name;
3876+
if (hasConflict) {
3877+
SmallString<64> nameBuf{name.str()};
3878+
nameBuf += SWIFT_PROTOCOL_SUFFIX;
3879+
name = Impl.SwiftContext.getIdentifier(nameBuf.str());
3880+
}
3881+
38463882
auto dc = Impl.importDeclContextOf(decl);
38473883
if (!dc)
38483884
return nullptr;
@@ -3860,7 +3896,7 @@ namespace {
38603896
name,
38613897
None);
38623898
result->computeType();
3863-
addObjCAttribute(result, ObjCSelector(Impl.SwiftContext, 0, origName));
3899+
addObjCAttribute(result, origName);
38643900

38653901
if (declaredNative)
38663902
markMissingSwiftDecl(result);
@@ -3951,7 +3987,7 @@ namespace {
39513987
result->setSuperclass(nsObjectTy);
39523988
result->setCheckedInheritanceClause();
39533989
result->setAddedImplicitInitializers();
3954-
addObjCAttribute(result, ObjCSelector(Impl.SwiftContext, 0, name));
3990+
addObjCAttribute(result, name);
39553991
Impl.registerExternalDecl(result);
39563992
return result;
39573993
}
@@ -3990,7 +4026,7 @@ namespace {
39904026
Impl.ImportedDecls[decl->getCanonicalDecl()] = result;
39914027
result->setCircularityCheck(CircularityCheck::Checked);
39924028
result->setAddedImplicitInitializers();
3993-
addObjCAttribute(result, ObjCSelector(Impl.SwiftContext, 0, name));
4029+
addObjCAttribute(result, name);
39944030

39954031
if (declaredNative)
39964032
markMissingSwiftDecl(result);

lib/ClangImporter/ImporterImpl.h

+3
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ enum class SpecialMethodKind {
185185

186186
#define SWIFT_NATIVE_ANNOTATION_STRING "__swift native"
187187

188+
#define SWIFT_PROTOCOL_SUFFIX "Protocol"
189+
#define SWIFT_CFTYPE_SUFFIX "Ref"
190+
188191
/// Describes whether to classify a factory method as an initializer.
189192
enum class FactoryAsInitKind {
190193
/// Infer based on name and type (the default).

lib/PrintAsObjC/PrintAsObjC.cpp

+6-8
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,12 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
8787
os << " <";
8888
interleave(protosToPrint,
8989
[this](const ProtocolDecl *PD) {
90-
auto Name = PD->getName().str();
91-
// Remap back to the original protocol name that may
92-
// have been changed during import.
93-
Name = llvm::StringSwitch<StringRef>(Name)
94-
#define RENAMED_PROTOCOL(ObjCName, SwiftName) .Case(#SwiftName, #ObjCName)
95-
#include "swift/ClangImporter/RenamedProtocols.def"
96-
.Default(Name);
97-
os << Name;
90+
if (PD->hasClangNode()) {
91+
SmallString<64> buf;
92+
os << PD->getObjCRuntimeName(buf);
93+
} else {
94+
os << PD->getName().str();
95+
}
9896
},
9997
[this] { os << ", "; });
10098
os << ">";

test/ClangModules/Inputs/custom-modules/ObjCParseExtras.h

+4
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ __attribute__((objc_root_class))
6060
- (void)setObject:(id)obj atIndexedSubscript:(int)i;
6161
@end
6262

63+
@protocol ProtoOrClass
64+
@property int thisIsTheProto;
65+
@end
66+
6367

6468
#pragma mark Constant global properties
6569

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@import ObjCParseExtrasTooHelper;
2+
3+
@interface ProtoOrClass
4+
@property int thisClassHasAnAwfulName;
5+
@end
6+
7+
8+
@protocol ClassInHelper
9+
@end
10+
11+
@interface ProtoInHelper
12+
- (instancetype)init;
13+
@end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@interface ClassInHelper
2+
- (instancetype)init;
3+
@end
4+
5+
@protocol ProtoInHelper
6+
@end

0 commit comments

Comments
 (0)