Skip to content

Commit 7f23007

Browse files
milsemantkremenek
authored andcommitted
Newtype fixit 3.0 (#2752)
* [Import as Member] Print full context in fixit Due to swift_name and swift_newtype, we are frequently importing onto different contexts. This was confusing the fixit logic for unavailable swift2 names, as we were trying to use Clang names when the Swift name might be totally different (and even a nested type). This change has a two-fold effect: 1) Globals who are imported onto swift_newtype-ed typedefs should be considered ImportAsMember. 2) When printing out the name of an ImportAsMember Swift 3 decl, we need to print out a fully qualified context, which also uses the Swift names, not the Clang names. * [swift_newtype] Also test for the right FIXIT
1 parent e51c883 commit 7f23007

File tree

5 files changed

+112
-31
lines changed

5 files changed

+112
-31
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1893,12 +1893,48 @@ namespace {
18931893
typedef ClangImporter::Implementation::ImportedName ImportedName;
18941894
}
18951895

1896-
void ClangImporter::Implementation::ImportedName::printSwiftName(
1897-
llvm::raw_ostream &os) const {
1896+
/// Will recursively print out the fully qualified context for the given name.
1897+
/// Ends with a trailing "."
1898+
static void
1899+
printFullContextPrefix(ClangImporter::Implementation::ImportedName name,
1900+
llvm::raw_ostream &os,
1901+
ClangImporter::Implementation &Impl) {
1902+
const clang::NamedDecl *newDeclContextNamed = nullptr;
1903+
switch (name.EffectiveContext.getKind()) {
1904+
case EffectiveClangContext::UnresolvedContext:
1905+
os << name.EffectiveContext.getUnresolvedName() << ".";
1906+
// And we're done!
1907+
return;
1908+
1909+
case EffectiveClangContext::DeclContext: {
1910+
auto namedDecl =
1911+
dyn_cast<clang::NamedDecl>(name.EffectiveContext.getAsDeclContext());
1912+
if (!namedDecl) {
1913+
// We're done
1914+
return;
1915+
}
1916+
newDeclContextNamed = cast<clang::NamedDecl>(namedDecl);
1917+
break;
1918+
}
1919+
1920+
case EffectiveClangContext::TypedefContext:
1921+
newDeclContextNamed = name.EffectiveContext.getTypedefName();
1922+
break;
1923+
}
1924+
1925+
// Now, let's print out the parent
1926+
assert(newDeclContextNamed && "should of been set");
1927+
auto parentName = Impl.importFullName(newDeclContextNamed);
1928+
printFullContextPrefix(parentName, os, Impl);
1929+
os << parentName.Imported << ".";
1930+
}
1931+
1932+
void ClangImporter::Implementation::printSwiftName(ImportedName name,
1933+
llvm::raw_ostream &os) {
18981934
// Property accessors.
18991935
bool isGetter = false;
19001936
bool isSetter = false;
1901-
switch (AccessorKind) {
1937+
switch (name.AccessorKind) {
19021938
case ImportedAccessorKind::None:
19031939
break;
19041940

@@ -1917,43 +1953,27 @@ void ClangImporter::Implementation::ImportedName::printSwiftName(
19171953

19181954
// If we're importing a global as a member, we need to provide the
19191955
// effective context.
1920-
if (ImportAsMember) {
1921-
switch (EffectiveContext.getKind()) {
1922-
case EffectiveClangContext::DeclContext:
1923-
os << SwiftLookupTable::translateDeclContext(
1924-
EffectiveContext.getAsDeclContext())->second;
1925-
break;
1926-
1927-
case EffectiveClangContext::TypedefContext:
1928-
os << EffectiveContext.getTypedefName()->getName();
1929-
break;
1930-
1931-
case EffectiveClangContext::UnresolvedContext:
1932-
os << EffectiveContext.getUnresolvedName();
1933-
break;
1934-
}
1935-
1936-
os << ".";
1937-
}
1956+
if (name.ImportAsMember)
1957+
printFullContextPrefix(name, os, *this);
19381958

19391959
// Base name.
1940-
os << Imported.getBaseName().str();
1960+
os << name.Imported.getBaseName().str();
19411961

19421962
// Determine the number of argument labels we'll be producing.
1943-
auto argumentNames = Imported.getArgumentNames();
1963+
auto argumentNames = name.Imported.getArgumentNames();
19441964
unsigned numArguments = argumentNames.size();
1945-
if (SelfIndex) ++numArguments;
1965+
if (name.SelfIndex) ++numArguments;
19461966
if (isSetter) ++numArguments;
19471967

19481968
// If the result is a simple name that is not a getter, we're done.
1949-
if (numArguments == 0 && Imported.isSimpleName() && !isGetter) return;
1969+
if (numArguments == 0 && name.Imported.isSimpleName() && !isGetter) return;
19501970

19511971
// We need to produce a function name.
19521972
os << "(";
19531973
unsigned currentArgName = 0;
19541974
for (unsigned i = 0; i != numArguments; ++i) {
19551975
// The "self" parameter.
1956-
if (SelfIndex && *SelfIndex == i) {
1976+
if (name.SelfIndex && *name.SelfIndex == i) {
19571977
os << "self:";
19581978
continue;
19591979
}
@@ -2357,6 +2377,7 @@ auto ClangImporter::Implementation::importFullName(
23572377
// Import onto a swift_newtype if present
23582378
} else if (auto newtypeDecl = findSwiftNewtype(D, clangSema, swift2Name)) {
23592379
result.EffectiveContext = newtypeDecl;
2380+
result.ImportAsMember = true;
23602381
// Everything else goes into its redeclaration context.
23612382
} else {
23622383
result.EffectiveContext = dc->getRedeclContext();

lib/ClangImporter/ImportDecl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,14 +1268,15 @@ namespace {
12681268

12691269
/// Mark the given declaration as the Swift 2 variant of a Swift 3
12701270
/// declaration with the given name.
1271-
static void markAsSwift2Variant(Decl *decl, ImportedName swift3Name) {
1271+
void markAsSwift2Variant(Decl *decl, ImportedName swift3Name,
1272+
DeclContext *newDC = nullptr) {
12721273
ASTContext &ctx = decl->getASTContext();
12731274

12741275
llvm::SmallString<64> renamed;
12751276
{
12761277
// Render a swift_name string.
12771278
llvm::raw_svector_ostream os(renamed);
1278-
swift3Name.printSwiftName(os);
1279+
Impl.printSwiftName(swift3Name, os);
12791280
}
12801281

12811282
auto attr = AvailableAttr::createUnconditional(

lib/ClangImporter/ImporterImpl.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -912,9 +912,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
912912
}
913913
}
914914

915-
/// Print this imported name as a string suitable for the swift_name
916-
/// attribute.
917-
void printSwiftName(llvm::raw_ostream &os) const;
918915
};
919916

920917
/// Flags that control the import of names in importFullName.
@@ -943,6 +940,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
943940
const clang::MacroInfo *macro,
944941
clang::ASTContext &clangCtx);
945942

943+
/// Print an imported name as a string suitable for the swift_name attribute.
944+
void printSwiftName(ImportedName, llvm::raw_ostream &os);
945+
946946
/// Retrieve the property type as determined by the given accessor.
947947
static clang::QualType
948948
getAccessorPropertyType(const clang::FunctionDecl *accessor, bool isSetter,

test/IDE/Inputs/custom-modules/Newtype.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,11 @@ extern MyABIOldTypeNS getMyABIOldTypeNS(void);
9494
extern void takeMyABINewTypeNonNullNS(__nonnull MyABINewTypeNS);
9595
extern void takeMyABIOldTypeNonNullNS(__nonnull MyABIOldTypeNS);
9696

97+
// Nested types
98+
typedef struct {int i;} NSSomeContext;
99+
100+
typedef NSString *NSSomeContextName __attribute((swift_newtype(struct)))
101+
__attribute((swift_name("NSSomeContext.Name")));
102+
103+
extern const NSSomeContextName NSMyContextName;
104+

test/IDE/newtype.swift

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,52 @@
9191
// PRINT-NEXT: }
9292
// PRINT-NEXT: func FooAudited() -> CFNewType
9393
// PRINT-NEXT: func FooUnaudited() -> Unmanaged<CFString>
94+
//
95+
// PRINT-NEXT: struct MyABINewType : RawRepresentable, _SwiftNewtypeWrapper {
96+
// PRINT-NEXT: init(_ rawValue: CFString)
97+
// PRINT-NEXT: init(rawValue: CFString)
98+
// PRINT-NEXT: let rawValue: CFString
99+
// PRINT-NEXT: }
100+
// PRINT-NEXT: typealias MyABIOldType = CFString
101+
// PRINT-NEXT: extension MyABINewType {
102+
// PRINT-NEXT: static let global: MyABINewType!
103+
// PRINT-NEXT: }
104+
// PRINT-NEXT: let kMyABIOldTypeGlobal: MyABIOldType!
105+
// PRINT-NEXT: func getMyABINewType() -> MyABINewType!
106+
// PRINT-NEXT: func getMyABIOldType() -> MyABIOldType!
107+
// PRINT-NEXT: func takeMyABINewType(_: MyABINewType!)
108+
// PRINT-NEXT: func takeMyABIOldType(_: MyABIOldType!)
109+
// PRINT-NEXT: func takeMyABINewTypeNonNull(_: MyABINewType)
110+
// PRINT-NEXT: func takeMyABIOldTypeNonNull(_: MyABIOldType)
111+
// PRINT-NEXT: struct MyABINewTypeNS : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable, Comparable, _ObjectiveCBridgeable {
112+
// PRINT-NEXT: init(_ rawValue: String)
113+
// PRINT-NEXT: init(rawValue: String)
114+
// PRINT-NEXT: var _rawValue: NSString
115+
// PRINT-NEXT: var rawValue: String { get }
116+
// PRINT-NEXT: }
117+
// PRINT-NEXT: typealias MyABIOldTypeNS = NSString
118+
// PRINT-NEXT: func getMyABINewTypeNS() -> MyABINewTypeNS!
119+
// PRINT-NEXT: func getMyABIOldTypeNS() -> String!
120+
// PRINT-NEXT: func takeMyABINewTypeNonNullNS(_: MyABINewTypeNS)
121+
// PRINT-NEXT: func takeMyABIOldTypeNonNullNS(_: String)
122+
//
123+
// PRINT-NEXT: struct NSSomeContext {
124+
// PRINT-NEXT: var i: Int32
125+
// PRINT-NEXT: init()
126+
// PRINT-NEXT: init(i: Int32)
127+
// PRINT-NEXT: }
128+
// PRINT-NEXT: extension NSSomeContext {
129+
// PRINT-NEXT: struct Name : RawRepresentable, _SwiftNewtypeWrapper, Equatable, Hashable, Comparable, _ObjectiveCBridgeable {
130+
// PRINT-NEXT: init(_ rawValue: String)
131+
// PRINT-NEXT: init(rawValue: String)
132+
// PRINT-NEXT: var _rawValue: NSString
133+
// PRINT-NEXT: var rawValue: String { get }
134+
// PRINT-NEXT: }
135+
// PRINT-NEXT: }
136+
// PRINT-NEXT: extension NSSomeContext.Name {
137+
// PRINT-NEXT: static let myContextName: NSSomeContext.Name
138+
// PRINT-NEXT: }
139+
94140
import Newtype
95141

96142
func tests() {
@@ -129,3 +175,8 @@ func testConformances(ed: ErrorDomain) {
129175
acceptComparable(ed)
130176
acceptObjectiveCBridgeable(ed)
131177
}
178+
179+
func testFixit() {
180+
let _ = NSMyContextName
181+
// expected-error@-1{{'NSMyContextName' has been renamed to 'NSSomeContext.Name.myContextName'}} {{10-25=NSSomeContext.Name.myContextName}}
182+
}

0 commit comments

Comments
 (0)