Skip to content

Commit 303a3e5

Browse files
committed
Start the Migrator library
The Swift 4 Migrator is invoked through either the driver and frontend with the -update-code flag. The basic pipeline in the frontend is: - Perform some list of syntactic fixes (there are currently none). - Perform N rounds of sema fix-its on the primary input file, currently set to 7 based on prior migrator seasons. Right now, this is just set to take any fix-it suggested by the compiler. - Emit a replacement map file, a JSON file describing replacements to a file that Xcode knows how to understand. Currently, the Migrator maintains a history of migration states along the way for debugging purposes. - Add -emit-remap frontend option This will indicate the EmitRemap frontend action. - Don't fork to a separte swift-update binary. This is going to be a mode of the compiler, invoked by the same flags. - Add -disable-migrator-fixits option Useful for debugging, this skips the phase in the Migrator that automatically applies fix-its suggested by the compiler. - Add -emit-migrated-file-path option This is used for testing/debugging scenarios. This takes the final migration state's output text and writes it to the file specified by this option. - Add -dump-migration-states-dir This dumps all of the migration states encountered during a migration run for a file to the given directory. For example, the compiler fix-it migration pass dumps the input file, the output file, and the remap file between the two. State output has the following naming convention: ${Index}-${MigrationPassName}-${What}.${extension}, such as: 1-FixitMigrationState-Input.swift rdar://problem/30926261
1 parent 9463b60 commit 303a3e5

36 files changed

+994
-104
lines changed

include/swift/Basic/SourceManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,8 @@ class SourceManager {
199199
return LLVMSourceMgr.FindLineNumber(Loc.Value, BufferID);
200200
}
201201

202+
StringRef getEntireTextForBuffer(unsigned BufferID) const;
203+
202204
StringRef extractText(CharSourceRange Range,
203205
Optional<unsigned> BufferID = None) const;
204206

include/swift/Driver/Driver.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,6 @@ class OutputInfo {
6666

6767
/// Compile and execute the inputs immediately
6868
Immediate,
69-
70-
/// Invoke swift-update with the compiler frontend options.
71-
UpdateCode,
7269
};
7370

7471
/// The mode in which the driver should invoke the frontend.
@@ -97,9 +94,6 @@ class OutputInfo {
9794

9895
/// Whether the compiler picked the current module name, rather than the user.
9996
bool ModuleNameIsFallback = false;
100-
101-
// Whether the driver should generate compiler fixits as source edits.
102-
bool ShouldGenerateFixitEdits = false;
10397

10498
/// The number of threads for multi-threaded compilation.
10599
unsigned numThreads = 0;

include/swift/Frontend/Frontend.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "swift/ClangImporter/ClangImporter.h"
3434
#include "swift/ClangImporter/ClangImporterOptions.h"
3535
#include "swift/Frontend/FrontendOptions.h"
36+
#include "swift/Migrator/MigratorOptions.h"
3637
#include "swift/Sema/SourceLoader.h"
3738
#include "swift/Serialization/Validation.h"
3839
#include "swift/SIL/SILModule.h"
@@ -62,6 +63,7 @@ class CompilerInvocation {
6263
ClangImporterOptions ClangImporterOpts;
6364
SearchPathOptions SearchPathOpts;
6465
DiagnosticOptions DiagnosticOpts;
66+
MigratorOptions MigratorOpts;
6567
SILOptions SILOpts;
6668
IRGenOptions IRGenOpts;
6769

@@ -202,6 +204,10 @@ class CompilerInvocation {
202204
return DiagnosticOpts;
203205
}
204206

207+
const MigratorOptions &getMigratorOptions() const {
208+
return MigratorOpts;
209+
}
210+
205211
SILOptions &getSILOptions() { return SILOpts; }
206212
const SILOptions &getSILOptions() const { return SILOpts; }
207213

include/swift/Frontend/FrontendOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ class FrontendOptions {
169169
EmitIR, ///< Emit LLVM IR
170170
EmitBC, ///< Emit LLVM BC
171171
EmitObject, ///< Emit object file
172+
173+
UpdateCode, ///< Update Swift code
172174
};
173175

174176
/// Indicates the action the user requested that the frontend perform.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//===--- FixitApplyDiagnosticConsumer.h - ----------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This class records compiler interesting fix-its as textual edits.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_MIGRATOR_FIXITAPPLYDIAGNOSTICCONSUMER_H
18+
#define SWIFT_MIGRATOR_FIXITAPPLYDIAGNOSTICCONSUMER_H
19+
20+
#include "swift/AST/DiagnosticConsumer.h"
21+
#include "clang/Rewrite/Core/RewriteBuffer.h"
22+
23+
namespace swift {
24+
25+
class CompilerInvocation;
26+
struct DiagnosticInfo;
27+
struct MigratorOptions;
28+
class SourceManager;
29+
30+
namespace migrator {
31+
32+
class Replacement;
33+
34+
class FixitApplyDiagnosticConsumer final : public DiagnosticConsumer {
35+
clang::RewriteBuffer RewriteBuf;
36+
37+
/// The Migrator options collected by the Swift CompilerInvocation,
38+
/// used to drive decisions about which fix-its to apply.
39+
const MigratorOptions &MigratorOpts;
40+
41+
/// The entire text of the input file.
42+
const StringRef Text;
43+
44+
/// The name of the buffer, which should be the absolute path of the input
45+
/// filename.
46+
const StringRef BufferName;
47+
48+
/// The number of fix-its pushed into the rewrite buffer. Use this to
49+
/// determine whether to call `printResult`.
50+
unsigned NumFixitsApplied;
51+
52+
/// A list of replacements that have been applied while diagnosing the
53+
/// input file.
54+
std::vector<Replacement> Replacements;
55+
56+
/// Returns true if the fix-it should be applied.
57+
bool shouldTakeFixit(const DiagnosticInfo &Info,
58+
const DiagnosticInfo::FixIt &F) const;
59+
60+
public:
61+
FixitApplyDiagnosticConsumer(const MigratorOptions &MigratorOpts,
62+
const StringRef Text,
63+
const StringRef BufferName);
64+
65+
/// Print the resulting text, applying the caught fix-its to the given
66+
/// output stream.
67+
void printResult(llvm::raw_ostream &OS) const;
68+
69+
const std::vector<Replacement> &getReplacements() const {
70+
return Replacements;
71+
}
72+
73+
void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
74+
DiagnosticKind Kind,
75+
StringRef FormatString,
76+
ArrayRef<DiagnosticArgument> FormatArgs,
77+
const DiagnosticInfo &Info) override;
78+
79+
unsigned getNumFixitsApplied() const {
80+
return NumFixitsApplied;
81+
}
82+
};
83+
} // end namespace migrator
84+
} // end namespace swift
85+
86+
#endif // SWIFT_MIGRATOR_FIXITAPPLYDIAGNOSTICCONSUMER_H
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//===--- MigrationState.h - Migration State --------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This class is an explicit container for a state during migration, its input
14+
// and output text, as well as what created this state.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#ifndef SWIFT_MIGRATOR_MIGRATIONSTATE_H
19+
#define SWIFT_MIGRATOR_MIGRATIONSTATE_H
20+
21+
#include "swift/Migrator/Replacement.h"
22+
#include "swift/Syntax/References.h"
23+
#include "llvm/ADT/IntrusiveRefCntPtr.h"
24+
#include "llvm/ADT/StringRef.h"
25+
26+
namespace swift {
27+
28+
class SourceManager;
29+
30+
namespace migrator {
31+
32+
enum class MigrationKind {
33+
/// The compiler has made several passes over the input file and we
34+
/// applied the suggested fix-its we deemed appropriate.
35+
CompilerFixits,
36+
};
37+
38+
struct MigrationState : public llvm::ThreadSafeRefCountedBase<MigrationState> {
39+
const MigrationKind Kind;
40+
SourceManager &SrcMgr;
41+
42+
MigrationState(const MigrationKind Kind, SourceManager &SrcMgr)
43+
: Kind(Kind), SrcMgr(SrcMgr) {}
44+
45+
MigrationKind getKind() const {
46+
return Kind;
47+
}
48+
49+
std::string getInputText() const;
50+
std::string getOutputText() const;
51+
52+
/// Write all relevant information about the state to OutDir, such as the
53+
/// input file, output file, replacements, syntax trees, etc.
54+
bool print(size_t StateNumber, StringRef OutDir) const;
55+
};
56+
57+
struct FixitMigrationState final : public MigrationState {
58+
const unsigned InputBufferID;
59+
const unsigned OutputBufferID;
60+
const std::vector<Replacement> Replacements;
61+
62+
// Other information about the migration?
63+
64+
FixitMigrationState(SourceManager &SrcMgr,
65+
const unsigned InputBufferID,
66+
const unsigned OutputBufferID,
67+
const std::vector<Replacement> &Replacements)
68+
: MigrationState(MigrationKind::CompilerFixits, SrcMgr),
69+
InputBufferID(InputBufferID),
70+
OutputBufferID(OutputBufferID),
71+
Replacements(Replacements) {}
72+
73+
std::string getInputText() const;
74+
75+
unsigned getInputBufferID() const {
76+
return InputBufferID;
77+
}
78+
79+
std::string getOutputText() const;
80+
81+
unsigned getOutputBufferID() const {
82+
return OutputBufferID;
83+
}
84+
85+
bool print(size_t StateNumber, StringRef OutDir) const;
86+
87+
bool outputDiffersFromInput() const {
88+
return InputBufferID != OutputBufferID;
89+
}
90+
91+
/// Dump the remap between the current input and output text.
92+
void dumpRemap() const;
93+
94+
static RC<FixitMigrationState>
95+
make(SourceManager &SrcMgr, const unsigned InputBufferID,
96+
const unsigned OutputBufferID,
97+
const std::vector<Replacement> &Replacements) {
98+
return RC<FixitMigrationState> {
99+
new FixitMigrationState {
100+
SrcMgr,
101+
InputBufferID,
102+
// The input is the output here, because nothing happened yet.
103+
OutputBufferID,
104+
Replacements
105+
}
106+
};
107+
}
108+
109+
static RC<FixitMigrationState>
110+
start(SourceManager &SrcMgr, const unsigned InputBufferID) {
111+
return make(SrcMgr, InputBufferID, InputBufferID, {});
112+
}
113+
114+
static bool classof(const MigrationState *MS) {
115+
return MS->getKind() == MigrationKind::CompilerFixits;
116+
}
117+
};
118+
119+
}
120+
}
121+
#endif // SWIFT_MIGRATOR_MIGRATIONSTATE_H

include/swift/Migrator/Migrator.h

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//===--- Migrator.h - Migrator ----------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// The top-level Swift Migrator driver.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_MIGRATOR_MIGRATOR_H
18+
#define SWIFT_MIGRATOR_MIGRATOR_H
19+
20+
#include "swift/Migrator/MigrationState.h"
21+
#include "swift/Migrator/Replacement.h"
22+
#include "swift/Syntax/References.h"
23+
24+
namespace swift {
25+
class CompilerInstance;
26+
27+
namespace migrator {
28+
29+
/// Run the migrator on the compiler invocation's input file and emit a
30+
/// "replacement map" describing the requested changes to the source file.
31+
bool updateCodeAndEmitRemap(CompilerInstance &Instance,
32+
const CompilerInvocation &Invocation);
33+
34+
class Migrator {
35+
CompilerInstance &StartInstance;
36+
const CompilerInvocation &StartInvocation;
37+
SourceManager SrcMgr;
38+
std::vector<RC<MigrationState>> States;
39+
40+
public:
41+
Migrator(CompilerInstance &StartInstance,
42+
const CompilerInvocation &StartInvocation);
43+
44+
/// The maximum number of times to run the compiler over the input to get
45+
/// fix-its. Nullability changes may expose other fix-its in subsequent
46+
/// compilations.
47+
static constexpr unsigned MaxCompilerFixitPassIterations = 7;
48+
49+
/// Repeatedly perform a number of compielr-fix-it migrations in a row, until
50+
/// there are no new suggestions from the compiler or some other error
51+
/// occurred.
52+
void repeatFixitMigrations(const unsigned Iterations);
53+
54+
/// Perform a single compiler fix-it migration on the last state, and push
55+
/// the result onto the state history.
56+
llvm::Optional<RC<FixitMigrationState>> performAFixItMigration();
57+
58+
/// Starting with the last state, perform the following migration passes.
59+
llvm::Optional<RC<MigrationState>> performSyntacticPasses(/*, Array of passes */);
60+
61+
/// Populate an array of replacements representing the difference between
62+
/// the start state's text and the end state's text.
63+
void getReplacements(SmallVectorImpl<Replacement> &Replacements) const;
64+
65+
/// Emit the output text of the final state in States to the path specified
66+
/// by -emit-migrated-file-path in StartInvocation.MigratorOptions.
67+
///
68+
/// Returns true if an attempt was made and failed.
69+
bool emitMigratedFile() const;
70+
71+
/// Dump all of the migration states encountered so far to
72+
/// StartInvocation.MigratorOptions.DumpMigrationStatesDir.
73+
///
74+
/// Returns true if an attempt was made and failed.
75+
bool dumpStates() const;
76+
77+
/// Get the options for the Migrator.
78+
const MigratorOptions &getMigratorOptions() const;
79+
80+
/// Get the filename of the input given by this->StartInvocation.
81+
const StringRef getInputFilename() const;
82+
};
83+
84+
} // end namespace migrator
85+
} // end namespace swift
86+
87+
#endif // SWIFT_MIGRATOR_MIGRATOR_H

0 commit comments

Comments
 (0)