Skip to content

Commit c956106

Browse files
authored
Merge pull request #9277 from bitjammer/github-merge-migrator-swift-4.0-branch
GitHub merge Migrator -> swift 4.0 branch
2 parents 856c0c7 + acba0ec commit c956106

16 files changed

+314
-41
lines changed

include/swift/Migrator/FixitFilter.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ struct FixitFilter {
7777
return false;
7878
}
7979

80+
// With SE-110, the migrator may get a recommendation to add a Void
81+
// placeholder in the call to f in:
82+
// func foo(f: (Void) -> ()) {
83+
// f()
84+
// }
85+
// Here, f was () -> () in Swift 3 but now (()) -> () in Swift 4. Adding a
86+
// type placeholder in the f() call isn't helpful for migration, although
87+
// this particular fix-it should be to fix the f parameter's type.
88+
if (Info.ID == diag::missing_argument_named.ID ||
89+
Info.ID == diag::missing_argument_positional.ID) {
90+
return false;
91+
}
92+
8093
if (Kind == DiagnosticKind::Error)
8194
return true;
8295

include/swift/Migrator/MigrationState.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ struct MigrationState : public llvm::ThreadSafeRefCountedBase<MigrationState> {
7474
/// input file, output file, replacements, syntax trees, etc.
7575
bool print(size_t StateNumber, StringRef OutDir) const;
7676

77-
bool outputDiffersFromInput() const {
78-
return InputBufferID != OutputBufferID;
77+
bool noChangesOccurred() const {
78+
return InputBufferID == OutputBufferID;
7979
}
8080

8181
static RC<MigrationState>

include/swift/Migrator/Migrator.h

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,16 @@ namespace migrator {
2727

2828
/// Run the migrator on the compiler invocation's input file and emit a
2929
/// "replacement map" describing the requested changes to the source file.
30-
bool updateCodeAndEmitRemap(CompilerInstance &Instance,
30+
bool updateCodeAndEmitRemap(CompilerInstance *Instance,
3131
const CompilerInvocation &Invocation);
3232

33-
class Migrator {
34-
CompilerInstance &StartInstance;
33+
struct Migrator {
34+
CompilerInstance *StartInstance;
3535
const CompilerInvocation &StartInvocation;
3636
SourceManager SrcMgr;
3737
std::vector<RC<MigrationState>> States;
3838

39-
public:
40-
Migrator(CompilerInstance &StartInstance,
39+
Migrator(CompilerInstance *StartInstance,
4140
const CompilerInvocation &StartInvocation);
4241

4342
/// The maximum number of times to run the compiler over the input to get
@@ -48,11 +47,21 @@ class Migrator {
4847
/// Repeatedly perform a number of compiler-fix-it migrations in a row, until
4948
/// there are no new suggestions from the compiler or some other error
5049
/// occurred.
51-
void repeatFixitMigrations(const unsigned Iterations);
50+
///
51+
/// Returns the last CompilerInstance used in the iterations, provided
52+
/// that the CompilerInvocation used to set it up was successful. Otherwise,
53+
/// returns nullptr.
54+
std::unique_ptr<swift::CompilerInstance>
55+
repeatFixitMigrations(const unsigned Iterations,
56+
swift::version::Version SwiftLanguageVersion);
5257

5358
/// Perform a single compiler fix-it migration on the last state, and push
5459
/// the result onto the state history.
55-
llvm::Optional<RC<MigrationState>> performAFixItMigration();
60+
///
61+
/// Returns the CompilerInstance used for the fix-it run, provided its
62+
/// setup from a CompilerInvocation was successful.
63+
std::unique_ptr<swift::CompilerInstance>
64+
performAFixItMigration(swift::version::Version SwiftLanguageVersion);
5665

5766
/// Starting with the last state, perform the following migration passes.
5867
///

lib/FrontendTool/FrontendTool.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -517,9 +517,8 @@ static bool performCompile(std::unique_ptr<CompilerInstance> &Instance,
517517

518518
ASTContext &Context = Instance->getASTContext();
519519

520-
if (!Context.hadError() &&
521-
Invocation.getMigratorOptions().shouldRunMigrator()) {
522-
migrator::updateCodeAndEmitRemap(*Instance, Invocation);
520+
if (Invocation.getMigratorOptions().shouldRunMigrator()) {
521+
migrator::updateCodeAndEmitRemap(Instance.get(), Invocation);
523522
}
524523

525524
if (Action == FrontendOptions::REPL) {

lib/Migrator/Migrator.cpp

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,41 @@
2525
using namespace swift;
2626
using namespace swift::migrator;
2727

28-
bool migrator::updateCodeAndEmitRemap(CompilerInstance &Instance,
28+
bool migrator::updateCodeAndEmitRemap(CompilerInstance *Instance,
2929
const CompilerInvocation &Invocation) {
3030
Migrator M { Instance, Invocation }; // Provide inputs and configuration
3131

32-
// Phase 1:
33-
// Perform any syntactic transformations if requested.
32+
// Phase 1: Pre Fix-it passes
33+
// These uses the initial frontend invocation to apply any obvious fix-its
34+
// to see if we can get an error-free AST to get to Phase 2.
35+
std::unique_ptr<swift::CompilerInstance> PreFixItInstance;
36+
if (Instance->getASTContext().hadError()) {
37+
PreFixItInstance = M.repeatFixitMigrations(2,
38+
Invocation.getLangOptions().EffectiveLanguageVersion);
39+
40+
// If we still couldn't fix all of the errors, give up.
41+
if (PreFixItInstance->getASTContext().hadError()) {
42+
return true;
43+
}
44+
M.StartInstance = PreFixItInstance.get();
45+
}
3446

47+
// Phase 2: Syntactic Transformations
3548
auto FailedSyntacticPasses = M.performSyntacticPasses();
3649
if (FailedSyntacticPasses) {
3750
return true;
3851
}
3952

40-
// Phase 2:
53+
// Phase 3: Post Fix-it Passes
4154
// Perform fix-it based migrations on the compiler, some number of times in
4255
// order to give the compiler an opportunity to
4356
// take its time reaching a fixed point.
57+
// This is the end of the pipeline, so we throw away the compiler instance(s)
58+
// we used in these fix-it runs.
4459

4560
if (M.getMigratorOptions().EnableMigratorFixits) {
46-
M.repeatFixitMigrations(Migrator::MaxCompilerFixitPassIterations);
61+
M.repeatFixitMigrations(Migrator::MaxCompilerFixitPassIterations,
62+
{4, 0, 0});
4763
}
4864

4965
// OK, we have a final resulting text. Now we compare against the input
@@ -58,7 +74,7 @@ bool migrator::updateCodeAndEmitRemap(CompilerInstance &Instance,
5874
return EmitRemapFailed || EmitMigratedFailed || DumpMigrationStatesFailed;
5975
}
6076

61-
Migrator::Migrator(CompilerInstance &StartInstance,
77+
Migrator::Migrator(CompilerInstance *StartInstance,
6278
const CompilerInvocation &StartInvocation)
6379
: StartInstance(StartInstance), StartInvocation(StartInvocation) {
6480

@@ -68,33 +84,32 @@ Migrator::Migrator(CompilerInstance &StartInstance,
6884
States.push_back(MigrationState::start(SrcMgr, StartBufferID));
6985
}
7086

71-
void Migrator::
72-
repeatFixitMigrations(const unsigned Iterations) {
87+
std::unique_ptr<swift::CompilerInstance>
88+
Migrator::repeatFixitMigrations(const unsigned Iterations,
89+
version::Version SwiftLanguageVersion) {
7390
for (unsigned i = 0; i < Iterations; ++i) {
74-
auto ThisResult = performAFixItMigration();
75-
if (!ThisResult.hasValue()) {
76-
// Something went wrong? Track error in the state?
91+
auto ThisInstance = performAFixItMigration(SwiftLanguageVersion);
92+
if (ThisInstance == nullptr) {
7793
break;
7894
} else {
79-
if (ThisResult.getValue()->outputDiffersFromInput()) {
80-
States.push_back(ThisResult.getValue());
81-
} else {
82-
break;
95+
if (States.back()->noChangesOccurred()) {
96+
return ThisInstance;
8397
}
8498
}
8599
}
100+
return nullptr;
86101
}
87102

88-
llvm::Optional<RC<MigrationState>>
89-
Migrator::performAFixItMigration() {
103+
std::unique_ptr<swift::CompilerInstance>
104+
Migrator::performAFixItMigration(version::Version SwiftLanguageVersion) {
90105
auto InputState = States.back();
91106
auto InputBuffer =
92107
llvm::MemoryBuffer::getMemBufferCopy(InputState->getOutputText(),
93108
getInputFilename());
94109

95110
CompilerInvocation Invocation { StartInvocation };
96111
Invocation.clearInputs();
97-
Invocation.getLangOptions().EffectiveLanguageVersion = { 4, 0, 0 };
112+
Invocation.getLangOptions().EffectiveLanguageVersion = SwiftLanguageVersion;
98113

99114
// SE-0160: When migrating, always use the Swift 3 @objc inference rules,
100115
// which drives warnings with the "@objc" Fix-Its.
@@ -132,18 +147,18 @@ Migrator::performAFixItMigration() {
132147
PrimaryIndex, SelectedInput::InputKind::Buffer
133148
};
134149

135-
CompilerInstance Instance;
136-
if (Instance.setup(Invocation)) {
137-
return None;
150+
auto Instance = llvm::make_unique<swift::CompilerInstance>();
151+
if (Instance->setup(Invocation)) {
152+
return nullptr;
138153
}
139154

140155
FixitApplyDiagnosticConsumer FixitApplyConsumer {
141156
InputState->getOutputText(),
142157
getInputFilename(),
143158
};
144-
Instance.addDiagnosticConsumer(&FixitApplyConsumer);
159+
Instance->addDiagnosticConsumer(&FixitApplyConsumer);
145160

146-
Instance.performSema();
161+
Instance->performSema();
147162

148163
StringRef ResultText = InputState->getOutputText();
149164
unsigned ResultBufferID = InputState->getOutputBufferID();
@@ -157,9 +172,10 @@ Migrator::performAFixItMigration() {
157172
ResultBufferID = SrcMgr.addNewSourceBuffer(std::move(ResultBuffer));
158173
}
159174

160-
return MigrationState::make(MigrationKind::CompilerFixits,
161-
SrcMgr, InputState->getOutputBufferID(),
162-
ResultBufferID);
175+
States.push_back(MigrationState::make(MigrationKind::CompilerFixits,
176+
SrcMgr, InputState->getOutputBufferID(),
177+
ResultBufferID));
178+
return Instance;
163179
}
164180

165181
bool Migrator::performSyntacticPasses() {
@@ -181,7 +197,7 @@ bool Migrator::performSyntacticPasses() {
181197

182198
auto InputState = States.back();
183199

184-
EditorAdapter Editor { StartInstance.getSourceMgr(), ClangSourceManager };
200+
EditorAdapter Editor { StartInstance->getSourceMgr(), ClangSourceManager };
185201

186202
// const auto SF = Instance.getPrimarySourceFile();
187203

@@ -195,7 +211,7 @@ bool Migrator::performSyntacticPasses() {
195211
// Once it has run, push the edits into Edits above:
196212
// Edits.commit(YourPass.getEdits());
197213

198-
SyntacticMigratorPass SPass(Editor, StartInstance.getPrimarySourceFile(),
214+
SyntacticMigratorPass SPass(Editor, StartInstance->getPrimarySourceFile(),
199215
getMigratorOptions());
200216
SPass.run();
201217
Edits.commit(SPass.getEdits());
@@ -207,7 +223,7 @@ bool Migrator::performSyntacticPasses() {
207223
RewriteBufferEditsReceiver Rewriter {
208224
ClangSourceManager,
209225
Editor.getClangFileIDForSwiftBufferID(
210-
StartInstance.getPrimarySourceFile()->getBufferID().getValue()),
226+
StartInstance->getPrimarySourceFile()->getBufferID().getValue()),
211227
InputState->getOutputText()
212228
};
213229

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
func foo(f: (Void) -> ()) {
2+
f()
3+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
let s = "foo"
2+
let ss = s[s.startIndex..<s.endIndex]
3+
4+
// CTP_ReturnStmt
5+
func returnStringButWantedSubstring() -> Substring {
6+
return s
7+
}
8+
9+
// CTP_DefaultParameter
10+
// Never do this.
11+
func defaultArgIsSubstring(ss: Substring = s) {}
12+
13+
// CTP_CalleeResult
14+
func returnString() -> String {
15+
return s
16+
}
17+
let s2: Substring = returnString()
18+
19+
// CTP_CallArgument
20+
func takeString(s: String) {}
21+
func takeSubstring(ss: Substring) {}
22+
23+
takeSubstring(ss)
24+
takeSubstring(s)
25+
26+
// CTP_ClosureResult
27+
[1,2,3].map { (x: Int) -> Substring in
28+
return s
29+
}
30+
31+
// CTP_ArrayElement
32+
let a: [Substring] = [ s ]
33+
34+
// CTP_DictionaryKey
35+
// CTP_DictionaryValue
36+
let d: [Substring : Substring] = [
37+
"CTP_DictionaryValue" : s,
38+
s : "CTP_DictionaryKey",
39+
]
40+
41+
// CTP_CoerceOperand
42+
let s3: Substring = s as Substring
43+
44+
// CTP_AssignSource
45+
let s4: Substring = s
46+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
let s = "foo"
2+
let ss = s[s.startIndex..<s.endIndex]
3+
4+
// CTP_ReturnStmt
5+
6+
func returnSubstringButWantedString() -> String {
7+
return ss
8+
}
9+
10+
// CTP_DefaultParameter
11+
12+
// Never do this.
13+
func defaultArgIsString(s: String = ss) {}
14+
15+
// CTP_CalleeResult
16+
func returnSubstring() -> Substring {
17+
return ss
18+
}
19+
let s2: String = returnSubstring()
20+
21+
// CTP_CallArgument
22+
func takeString(_ s: String) {}
23+
24+
takeString(s)
25+
takeString(ss)
26+
27+
// CTP_ClosureResult
28+
[1,2,3].map { (x: Int) -> String in
29+
return ss
30+
}
31+
32+
// CTP_ArrayElement
33+
let a: [String] = [ ss ]
34+
35+
// CTP_DictionaryKey
36+
// CTP_DictionaryValue
37+
let d: [String : String] = [
38+
"CTP_DictionaryValue" : ss,
39+
ss : "CTP_DictionaryKey",
40+
]
41+
42+
// CTP_CoerceOperand
43+
let s3: String = ss as String
44+
45+
// CTP_AssignSource
46+
let s4: String = ss
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// RUN: rm -rf %t && mkdir -p %t && %target-swift-frontend -c -primary-file %S/Inputs/ignore_type_placeholder.swift -emit-migrated-file-path %t/ignore_type_placeholder.swift.result -emit-remap-file-path %t/ignore_type_placeholder.swift.remap
2+
// RUN: %FileCheck %s < %t/ignore_type_placeholder.swift.result
3+
// CHECK-NOT: f(<#Void#>)

test/Migrator/pre_fixit_pass.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// REQUIRES: objc_interop
2+
// RUN: rm -rf %t && mkdir -p %t && not %target-swift-frontend -c -update-code -primary-file %s -F %S/mock-sdk -api-diff-data-file %S/API.json -emit-migrated-file-path %t/pre_fixit_pass.swift.result -o /dev/null
3+
// RUN: diff -u %S/pre_fixit_pass.swift.expected %t/pre_fixit_pass.swift.result
4+
5+
import Bar
6+
7+
struct New {}
8+
@available(*, unavailable, renamed: "New")
9+
struct Old {}
10+
Old()
11+
12+
func foo(_ a : PropertyUserInterface) {
13+
a.setField(1)
14+
_ = a.field()
15+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// REQUIRES: objc_interop
2+
// RUN: rm -rf %t && mkdir -p %t && not %target-swift-frontend -c -update-code -primary-file %s -F %S/mock-sdk -api-diff-data-file %S/API.json -emit-migrated-file-path %t/pre_fixit_pass.swift.result -o /dev/null
3+
// RUN: diff -u %S/pre_fixit_pass.swift.expected %t/pre_fixit_pass.swift.result
4+
5+
import Bar
6+
7+
struct New {}
8+
@available(*, unavailable, renamed: "New")
9+
struct Old {}
10+
New()
11+
12+
func foo(_ a : PropertyUserInterface) {
13+
a.Field = 1
14+
_ = a.field
15+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: rm -rf %t && mkdir -p %t && not %target-swift-frontend -c -update-code -primary-file %s -emit-migrated-file-path %t/pre_fixit_pass.swift.result -o /dev/null
2+
3+
// We shouldn't be able to successfully use the pre-fix-it passes to
4+
// fix this file before migration because there is a use of an
5+
// unresolved identifier 'bar'.
6+
7+
func foo(s: String) {}
8+
foo("Hello")
9+
bar("Hello") // Unresolved failure

0 commit comments

Comments
 (0)