mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[driver] Remove the 'swift-fixit' symlink and introduce '-emit-fixits-path' frontend option that
writes compiler fixits as source edits. Driver option '-fixit-code' adds '-emit-fixits-path' for all the frontend invocations. Swift SVN r27208
This commit is contained in:
@@ -46,6 +46,8 @@ ERROR(error_no_frontend_args, frontend, none,
|
||||
ERROR(error_no_such_file_or_directory,frontend,none,
|
||||
"no such file or directory: '%0'", (StringRef))
|
||||
|
||||
ERROR(cannot_open_file,frontend,none,
|
||||
"cannot open file '%0' (%1)", (StringRef, StringRef))
|
||||
ERROR(cannot_open_serialized_file,frontend,none,
|
||||
"cannot open file '%0' for diagnostics emission (%1)", (StringRef, StringRef))
|
||||
ERROR(error_open_input_file,frontend,none,
|
||||
|
||||
@@ -68,9 +68,6 @@ public:
|
||||
|
||||
/// Invoke swift-update with the compiler frontend options.
|
||||
UpdateCode,
|
||||
|
||||
/// Invoke swift-fixit with the compiler frontend options.
|
||||
FixCode,
|
||||
};
|
||||
|
||||
/// The mode in which the driver should invoke the frontend.
|
||||
@@ -100,6 +97,9 @@ public:
|
||||
/// Whether the compiler picked the current module name, rather than the user.
|
||||
bool ModuleNameIsFallback = false;
|
||||
|
||||
// Whether the driver should generate compiler fixits as source edits.
|
||||
bool ShouldGenerateFixitEdits = false;
|
||||
|
||||
/// The number of threads for multi-threaded compilation.
|
||||
unsigned numThreads = 0;
|
||||
|
||||
@@ -121,7 +121,6 @@ public:
|
||||
enum class DriverKind {
|
||||
Interactive, // swift
|
||||
Batch, // swiftc
|
||||
FixCode, // swift-fixit
|
||||
AutolinkExtract, // swift-autolink-extract
|
||||
};
|
||||
|
||||
|
||||
@@ -112,6 +112,9 @@ public:
|
||||
/// The path to which we should output a Swift reference dependencies file.
|
||||
std::string ReferenceDependenciesFilePath;
|
||||
|
||||
/// The path to which we should output a fixits as source edits.
|
||||
std::string FixitsOutputPath;
|
||||
|
||||
/// Arguments which should be passed in immediate mode.
|
||||
std::vector<std::string> ImmediateArgv;
|
||||
|
||||
|
||||
@@ -49,6 +49,10 @@ def serialize_diagnostics_path
|
||||
: Separate<["-"], "serialize-diagnostics-path">, MetaVarName<"<path>">,
|
||||
HelpText<"Output serialized diagnostics to <path>">;
|
||||
|
||||
def emit_fixits_path
|
||||
: Separate<["-"], "emit-fixits-path">, MetaVarName<"<path>">,
|
||||
HelpText<"Output compiler fixits as source edits to <path>">;
|
||||
|
||||
def verify : Flag<["-"], "verify">,
|
||||
HelpText<"Verify diagnostics against expected-{error|warning|note} "
|
||||
"annotations">;
|
||||
|
||||
@@ -84,7 +84,7 @@ def driver_use_frontend_path : Separate<["-"], "driver-use-frontend-path">,
|
||||
HelpText<"Use the given executable to perform compilations">;
|
||||
|
||||
def driver_mode : Joined<["--"], "driver-mode=">, Flags<[HelpHidden]>,
|
||||
HelpText<"Set the driver mode to either 'swift' or 'swiftc' or 'swift-fixit'">;
|
||||
HelpText<"Set the driver mode to either 'swift' or 'swiftc'">;
|
||||
|
||||
def help : Flag<["-", "--"], "help">,
|
||||
Flags<[FrontendOption, AutolinkExtractOption]>,
|
||||
@@ -336,8 +336,8 @@ def update_code : Flag<["-"], "update-code">,
|
||||
Flags<[HelpHidden, NoInteractiveOption, DoesNotAffectIncrementalBuild]>;
|
||||
|
||||
def fixit_code : Flag<["-"], "fixit-code">,
|
||||
HelpText<"Get compiler fixits as code edits">, ModeOpt,
|
||||
Flags<[HelpHidden, NoInteractiveOption, DoesNotAffectIncrementalBuild]>;
|
||||
HelpText<"Get compiler fixits as code edits">,
|
||||
Flags<[NoInteractiveOption, DoesNotAffectIncrementalBuild]>;
|
||||
|
||||
// No Output Modes
|
||||
def parse : Flag<["-"], "parse">,
|
||||
|
||||
@@ -93,8 +93,6 @@ void Driver::parseDriverKind(ArrayRef<const char *> Args) {
|
||||
llvm::StringSwitch<Optional<DriverKind>>(DriverName)
|
||||
.Case("swift", DriverKind::Interactive)
|
||||
.Case("swiftc", DriverKind::Batch)
|
||||
.Case("swift-fixit", DriverKind::FixCode)
|
||||
.Case("swift-update", DriverKind::FixCode) // FIXME: remove once fully transitioned.
|
||||
.Case("swift-autolink-extract", DriverKind::AutolinkExtract)
|
||||
.Default(None);
|
||||
|
||||
@@ -309,7 +307,9 @@ std::unique_ptr<Compilation> Driver::buildCompilation(
|
||||
|
||||
// For updating code we need to go through all the files and pick up changes,
|
||||
// even if they have compiler errors.
|
||||
if (OI.CompilerMode == OutputInfo::Mode::UpdateCode)
|
||||
// Also for getting bulk fixits.
|
||||
if (OI.CompilerMode == OutputInfo::Mode::UpdateCode ||
|
||||
OI.ShouldGenerateFixitEdits)
|
||||
C->setContinueBuildingAfterErrors();
|
||||
|
||||
if (OFM)
|
||||
@@ -674,10 +674,6 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,
|
||||
OI.CompilerMode = OutputInfo::Mode::UpdateCode;
|
||||
OI.CompilerOutputType = types::TY_Remapping;
|
||||
OI.LinkAction = LinkKind::None;
|
||||
} else if (Args.hasArg(options::OPT_fixit_code)) {
|
||||
OI.CompilerMode = OutputInfo::Mode::FixCode;
|
||||
OI.CompilerOutputType = types::TY_Remapping;
|
||||
OI.LinkAction = LinkKind::None;
|
||||
} else {
|
||||
diagnoseOutputModeArg(Diags, OutputModeArg, !Inputs.empty(), Args,
|
||||
driverKind == DriverKind::Interactive, Name);
|
||||
@@ -823,6 +819,10 @@ void Driver::buildOutputInfo(const ToolChain &TC, const DerivedArgList &Args,
|
||||
}
|
||||
}
|
||||
|
||||
if (Args.hasArg(options::OPT_fixit_code)) {
|
||||
OI.ShouldGenerateFixitEdits = true;
|
||||
}
|
||||
|
||||
{
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_sdk)) {
|
||||
OI.SDKPath = A->getValue();
|
||||
@@ -1032,7 +1032,6 @@ void Driver::buildActions(const ToolChain &TC,
|
||||
ActionList CompileActions;
|
||||
switch (OI.CompilerMode) {
|
||||
case OutputInfo::Mode::StandardCompile:
|
||||
case OutputInfo::Mode::FixCode:
|
||||
case OutputInfo::Mode::UpdateCode: {
|
||||
for (const InputPair &Input : Inputs) {
|
||||
types::ID InputType = Input.first;
|
||||
@@ -1631,6 +1630,26 @@ Job *Driver::buildJobsForAction(Compilation &C, const Action *A,
|
||||
}
|
||||
}
|
||||
|
||||
if (OI.ShouldGenerateFixitEdits && isa<CompileJobAction>(JA)) {
|
||||
StringRef OFMFixitsOutputPath;
|
||||
if (OutputMap) {
|
||||
auto iter = OutputMap->find(types::TY_Remapping);
|
||||
if (iter != OutputMap->end())
|
||||
OFMFixitsOutputPath = iter->second;
|
||||
}
|
||||
if (!OFMFixitsOutputPath.empty()) {
|
||||
Output->setAdditionalOutputForType(types::ID::TY_Remapping,
|
||||
OFMFixitsOutputPath);
|
||||
} else {
|
||||
llvm::SmallString<128> Path(Output->getPrimaryOutputFilenames()[0]);
|
||||
bool isTempFile = C.isTemporaryFile(Path);
|
||||
llvm::sys::path::replace_extension(Path, "remap");
|
||||
Output->setAdditionalOutputForType(types::ID::TY_Remapping, Path);
|
||||
if (isTempFile)
|
||||
C.addTemporaryFile(Path);
|
||||
}
|
||||
}
|
||||
|
||||
if (isa<CompileJobAction>(JA)) {
|
||||
// Choose the serialized diagnostics output path.
|
||||
if (C.getArgs().hasArg(options::OPT_serialize_diagnostics)) {
|
||||
@@ -1837,7 +1856,6 @@ void Driver::printHelp(bool ShowHidden) const {
|
||||
ExcludedFlagsBitmask |= options::NoInteractiveOption;
|
||||
break;
|
||||
case DriverKind::Batch:
|
||||
case DriverKind::FixCode:
|
||||
case DriverKind::AutolinkExtract:
|
||||
ExcludedFlagsBitmask |= options::NoBatchOption;
|
||||
break;
|
||||
|
||||
@@ -156,10 +156,6 @@ Job *Swift::constructJob(const JobAction &JA, std::unique_ptr<JobList> Inputs,
|
||||
SmallString<128> SwiftUpdatePath = llvm::sys::path::parent_path(Exec);
|
||||
llvm::sys::path::append(SwiftUpdatePath, "swift-update");
|
||||
Exec = Args.MakeArgString(SwiftUpdatePath.str());
|
||||
} else if (OI.CompilerMode == OutputInfo::Mode::FixCode) {
|
||||
SmallString<128> SwiftFixPath = llvm::sys::path::parent_path(Exec);
|
||||
llvm::sys::path::append(SwiftFixPath, "swift-fixit");
|
||||
Exec = Args.MakeArgString(SwiftFixPath.str());
|
||||
} else {
|
||||
// Invoke ourselves in -frontend mode.
|
||||
Arguments.push_back("-frontend");
|
||||
@@ -230,7 +226,6 @@ Job *Swift::constructJob(const JobAction &JA, std::unique_ptr<JobList> Inputs,
|
||||
case OutputInfo::Mode::REPL:
|
||||
FrontendModeOption = "-repl";
|
||||
break;
|
||||
case OutputInfo::Mode::FixCode:
|
||||
case OutputInfo::Mode::UpdateCode:
|
||||
// Make sure that adding '-update-code' will permit accepting all arguments
|
||||
// '-c' accepts.
|
||||
@@ -248,7 +243,6 @@ Job *Swift::constructJob(const JobAction &JA, std::unique_ptr<JobList> Inputs,
|
||||
// Add input arguments.
|
||||
switch (OI.CompilerMode) {
|
||||
case OutputInfo::Mode::StandardCompile:
|
||||
case OutputInfo::Mode::FixCode:
|
||||
case OutputInfo::Mode::UpdateCode: {
|
||||
if (isa<BackendJobAction>(JA)) {
|
||||
assert(Inputs->size() == 1 && "The Swift backend expects one input!");
|
||||
@@ -316,7 +310,6 @@ Job *Swift::constructJob(const JobAction &JA, std::unique_ptr<JobList> Inputs,
|
||||
switch (OI.CompilerMode) {
|
||||
case OutputInfo::Mode::StandardCompile:
|
||||
case OutputInfo::Mode::SingleCompile:
|
||||
case OutputInfo::Mode::FixCode:
|
||||
case OutputInfo::Mode::UpdateCode:
|
||||
break;
|
||||
case OutputInfo::Mode::Immediate:
|
||||
@@ -365,6 +358,13 @@ Job *Swift::constructJob(const JobAction &JA, std::unique_ptr<JobList> Inputs,
|
||||
Arguments.push_back(ReferenceDependenciesPath.c_str());
|
||||
}
|
||||
|
||||
const std::string &FixitsPath =
|
||||
Output->getAdditionalOutputForType(types::TY_Remapping);
|
||||
if (!FixitsPath.empty()) {
|
||||
Arguments.push_back("-emit-fixits-path");
|
||||
Arguments.push_back(FixitsPath.c_str());
|
||||
}
|
||||
|
||||
if (OI.numThreads > 0) {
|
||||
Arguments.push_back("-num-threads");
|
||||
Arguments.push_back(Args.MakeArgString(Twine(OI.numThreads)));
|
||||
|
||||
@@ -472,6 +472,10 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
|
||||
OPT_emit_objc_header_path,
|
||||
"h", false);
|
||||
|
||||
if (const Arg *A = Args.getLastArg(OPT_emit_fixits_path)) {
|
||||
Opts.FixitsOutputPath = A->getValue();
|
||||
}
|
||||
|
||||
bool IsSIB =
|
||||
Opts.RequestedAction == FrontendOptions::EmitSIB ||
|
||||
Opts.RequestedAction == FrontendOptions::EmitSIBGen;
|
||||
|
||||
@@ -101,9 +101,9 @@
|
||||
// UPDATE-CODE: -c{{ }}
|
||||
// UPDATE-CODE: -o {{.+}}.remap
|
||||
|
||||
// FIXIT-CODE: bin/swift-fixit
|
||||
// FIXIT-CODE: bin/swift
|
||||
// FIXIT-CODE: -c{{ }}
|
||||
// FIXIT-CODE: -o {{.+}}.remap
|
||||
// FIXIT-CODE: -emit-fixits-path {{.+}}.remap
|
||||
|
||||
|
||||
// NO-REFERENCE-DEPENDENCIES: bin/swift
|
||||
|
||||
8
test/FixCode/Inputs/t1.swift
Normal file
8
test/FixCode/Inputs/t1.swift
Normal file
@@ -0,0 +1,8 @@
|
||||
func foo1() {
|
||||
class Base {}
|
||||
class Derived : Base {}
|
||||
|
||||
var b : Base
|
||||
b as Derived
|
||||
undeclared_foo1
|
||||
}
|
||||
8
test/FixCode/Inputs/t1.swift.result
Normal file
8
test/FixCode/Inputs/t1.swift.result
Normal file
@@ -0,0 +1,8 @@
|
||||
func foo1() {
|
||||
class Base {}
|
||||
class Derived : Base {}
|
||||
|
||||
var b : Base
|
||||
b as! Derived
|
||||
undeclared_foo1
|
||||
}
|
||||
8
test/FixCode/Inputs/t2.swift
Normal file
8
test/FixCode/Inputs/t2.swift
Normal file
@@ -0,0 +1,8 @@
|
||||
func foo2() {
|
||||
class Base {}
|
||||
class Derived : Base {}
|
||||
|
||||
var b : Base
|
||||
b as Derived
|
||||
undeclared_foo2
|
||||
}
|
||||
8
test/FixCode/Inputs/t2.swift.result
Normal file
8
test/FixCode/Inputs/t2.swift.result
Normal file
@@ -0,0 +1,8 @@
|
||||
func foo2() {
|
||||
class Base {}
|
||||
class Derived : Base {}
|
||||
|
||||
var b : Base
|
||||
b as! Derived
|
||||
undeclared_foo2
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
// RUN: %swift-fixit -c -target %target-triple %s -o %t.remap -serialize-diagnostics-path %t.dia -emit-module-doc-path %t.doc -emit-module-path %t.mod
|
||||
// RUN: not %swift -parse -target %target-triple %s -emit-fixits-path %t.remap -serialize-diagnostics-path %t.dia
|
||||
// RUN: c-arcmt-test %t.remap | arcmt-test -verify-transformed-files %s.result
|
||||
// RUN: c-index-test -read-diagnostics %t.dia > %t.deserialized_diagnostics.txt 2>&1
|
||||
// RUN: FileCheck --input-file=%t.deserialized_diagnostics.txt %s
|
||||
|
||||
// CHECK: Number of diagnostics: 0
|
||||
// CHECK: Number of diagnostics: 2
|
||||
|
||||
class Base {}
|
||||
class Derived : Base {}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// RUN: %swift-fixit -c -target %target-triple %s -o %t.remap -serialize-diagnostics-path %t.dia -emit-module-doc-path %t.doc -emit-module-path %t.mod
|
||||
// RUN: not %swift -parse -target %target-triple %s -emit-fixits-path %t.remap -serialize-diagnostics-path %t.dia
|
||||
// RUN: c-arcmt-test %t.remap | arcmt-test -verify-transformed-files %s.result
|
||||
// RUN: c-index-test -read-diagnostics %t.dia > %t.deserialized_diagnostics.txt 2>&1
|
||||
// RUN: FileCheck --input-file=%t.deserialized_diagnostics.txt %s
|
||||
|
||||
// CHECK: Number of diagnostics: 0
|
||||
// CHECK: Number of diagnostics: 2
|
||||
|
||||
class Base {}
|
||||
class Derived : Base {}
|
||||
|
||||
8
test/FixCode/multi-inputs.swift
Normal file
8
test/FixCode/multi-inputs.swift
Normal file
@@ -0,0 +1,8 @@
|
||||
// RUN: mkdir -p %t.out
|
||||
// RUN: echo "{\"%S/Inputs/t1.swift\": {\"remap\": \"%t.out/t1.remap\"}, \"%S/Inputs/t2.swift\": {\"remap\": \"%t.out/t2.remap\"}}" > %t.json
|
||||
// RUN: not %swiftc_driver -target %target-triple -module-name Blah -fixit-code %S/Inputs/t1.swift %S/Inputs/t2.swift -emit-module -emit-module-path %t.mod -emit-objc-header -emit-objc-header-path %t.h -j 1 -output-file-map %t.json 2> %t.err.txt
|
||||
// RUN: c-arcmt-test %t.out/t1.remap %t.out/t2.remap | arcmt-test -verify-transformed-files %S/Inputs/t1.swift.result %S/Inputs/t2.swift.result
|
||||
// RUN: FileCheck --input-file=%t.err.txt %s
|
||||
|
||||
// CHECK: error: use of unresolved identifier 'undeclared_foo1'
|
||||
// CHECK: error: use of unresolved identifier 'undeclared_foo2'
|
||||
@@ -1,18 +0,0 @@
|
||||
// RUN: not %swift-fixit -target %target-triple %s -o %t.remap -serialize-diagnostics-path %t.dia
|
||||
// RUN: c-arcmt-test %t.remap | arcmt-test -verify-transformed-files %s.result
|
||||
// RUN: c-index-test -read-diagnostics %t.dia > %t.deserialized_diagnostics.txt 2>&1
|
||||
// RUN: FileCheck --input-file=%t.deserialized_diagnostics.txt %s
|
||||
|
||||
// CHECK: error: no such module
|
||||
// CHECK: error: use of unresolved identifier
|
||||
// CHECK: Number of diagnostics: 2
|
||||
|
||||
import NotFoundModule
|
||||
|
||||
class Base {}
|
||||
class Derived : Base {}
|
||||
|
||||
var b : Base
|
||||
b as Derived
|
||||
|
||||
undeclared()
|
||||
@@ -1,18 +0,0 @@
|
||||
// RUN: not %swift-fixit -target %target-triple %s -o %t.remap -serialize-diagnostics-path %t.dia
|
||||
// RUN: c-arcmt-test %t.remap | arcmt-test -verify-transformed-files %s.result
|
||||
// RUN: c-index-test -read-diagnostics %t.dia > %t.deserialized_diagnostics.txt 2>&1
|
||||
// RUN: FileCheck --input-file=%t.deserialized_diagnostics.txt %s
|
||||
|
||||
// CHECK: error: no such module
|
||||
// CHECK: error: use of unresolved identifier
|
||||
// CHECK: Number of diagnostics: 2
|
||||
|
||||
import NotFoundModule
|
||||
|
||||
class Base {}
|
||||
class Derived : Base {}
|
||||
|
||||
var b : Base
|
||||
b as! Derived
|
||||
|
||||
undeclared()
|
||||
@@ -1,7 +1,6 @@
|
||||
add_swift_executable(swift
|
||||
driver.cpp
|
||||
autolink_extract_main.cpp
|
||||
fixit_main.cpp
|
||||
frontend_main.cpp
|
||||
LINK_LIBRARIES
|
||||
swiftIDE
|
||||
@@ -20,10 +19,6 @@ add_custom_command(TARGET swift POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" "-E" "create_symlink" "swift" "swiftc"
|
||||
WORKING_DIRECTORY "${SWIFT_RUNTIME_OUTPUT_INTDIR}")
|
||||
|
||||
add_custom_command(TARGET swift POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" "-E" "create_symlink" "swift" "swift-fixit"
|
||||
WORKING_DIRECTORY "${SWIFT_RUNTIME_OUTPUT_INTDIR}")
|
||||
|
||||
add_custom_command(TARGET swift POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" "-E" "create_symlink" "swift" "swift-autolink-extract"
|
||||
WORKING_DIRECTORY "${SWIFT_RUNTIME_OUTPUT_INTDIR}")
|
||||
@@ -54,9 +49,6 @@ swift_install_in_component(compiler
|
||||
swift_install_in_component(compiler
|
||||
FILES "${SWIFT_RUNTIME_OUTPUT_INTDIR}/swiftc"
|
||||
DESTINATION "bin")
|
||||
swift_install_in_component(compiler
|
||||
FILES "${SWIFT_RUNTIME_OUTPUT_INTDIR}/swift-fixit"
|
||||
DESTINATION "bin")
|
||||
|
||||
if(SWIFT_HOST_VARIANT STREQUAL "LINUX")
|
||||
# No need for this on other platforms.
|
||||
|
||||
@@ -48,10 +48,6 @@ std::string getExecutablePath(const char *FirstArg) {
|
||||
extern int frontend_main(ArrayRef<const char *> Args, const char *Argv0,
|
||||
void *MainAddr);
|
||||
|
||||
/// Run 'swift-fixit'.
|
||||
extern int fixit_main(ArrayRef<const char *> Args, const char *Argv0,
|
||||
void *MainAddr);
|
||||
|
||||
/// Run 'swift-autolink-extract'.
|
||||
extern int autolink_extract_main(ArrayRef<const char *> Args, const char *Argv0,
|
||||
void *MainAddr);
|
||||
@@ -93,10 +89,6 @@ int main(int argc_, const char **argv_) {
|
||||
|
||||
Driver TheDriver(Path, llvm::sys::path::stem(argv[0]), argv, Diags);
|
||||
switch (TheDriver.getDriverKind()) {
|
||||
case Driver::DriverKind::FixCode:
|
||||
return fixit_main(TheDriver.getArgsWithoutProgramNameAndDriverMode(argv),
|
||||
argv[0],
|
||||
(void *)(intptr_t)getExecutablePath);
|
||||
case Driver::DriverKind::AutolinkExtract:
|
||||
return autolink_extract_main(
|
||||
TheDriver.getArgsWithoutProgramNameAndDriverMode(argv),
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
//===--- fixit_main.cpp - Get Swift compiler fixits ------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This tool turns Swift compiler fixits into file edits.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "swift/AST/DiagnosticsFrontend.h"
|
||||
#include "swift/Basic/SourceManager.h"
|
||||
#include "swift/Driver/FrontendUtil.h"
|
||||
#include "swift/Frontend/Frontend.h"
|
||||
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
|
||||
#include "swift/Frontend/SerializedDiagnosticConsumer.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
|
||||
using namespace swift;
|
||||
|
||||
namespace {
|
||||
|
||||
/// If there is an error with fixits it writes the fixits in json format and
|
||||
/// filters out the diagnostic.
|
||||
class JSONFixitWriter : public DiagnosticConsumer {
|
||||
llvm::raw_ostream &OS;
|
||||
SmallVector<DiagnosticConsumer *, 2> Consumers;
|
||||
bool HasUnfixedError = false;
|
||||
bool PrevErrorFilteredOut = false;
|
||||
|
||||
public:
|
||||
explicit JSONFixitWriter(llvm::raw_ostream &OS) : OS(OS) {
|
||||
OS << "[\n";
|
||||
}
|
||||
~JSONFixitWriter() {
|
||||
OS << "]\n";
|
||||
}
|
||||
|
||||
/// \brief Add an additional DiagnosticConsumer to receive diagnostics.
|
||||
void addConsumer(DiagnosticConsumer *Consumer) {
|
||||
Consumers.push_back(Consumer);
|
||||
}
|
||||
void addConsumers(std::vector<DiagnosticConsumer*> NewConsumers) {
|
||||
Consumers.append(NewConsumers.begin(), NewConsumers.end());
|
||||
}
|
||||
|
||||
bool hasUnfixedError() const { return HasUnfixedError; }
|
||||
|
||||
private:
|
||||
void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
|
||||
DiagnosticKind Kind, StringRef Text,
|
||||
const DiagnosticInfo &Info) override {
|
||||
if (Kind == DiagnosticKind::Note && PrevErrorFilteredOut)
|
||||
return;
|
||||
PrevErrorFilteredOut = false;
|
||||
|
||||
if (tryFixing(SM, Kind, Info)) {
|
||||
PrevErrorFilteredOut = true;
|
||||
return; // filter out.
|
||||
}
|
||||
|
||||
if (Kind == DiagnosticKind::Error)
|
||||
HasUnfixedError = true;
|
||||
// Transfer the diagnostic to other consumers.
|
||||
for (auto *Consumer : Consumers)
|
||||
Consumer->handleDiagnostic(SM, Loc, Kind, Text, Info);
|
||||
}
|
||||
|
||||
bool tryFixing(SourceManager &SM,
|
||||
DiagnosticKind Kind,
|
||||
const DiagnosticInfo &Info) {
|
||||
if (Kind != DiagnosticKind::Error)
|
||||
return false;
|
||||
if (Info.FixIts.empty())
|
||||
return false;
|
||||
for (const auto &Fix : Info.FixIts) {
|
||||
writeEdit(SM, Fix.getRange(), Fix.getText(), OS);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void writeEdit(SourceManager &SM, CharSourceRange Range, StringRef Text,
|
||||
llvm::raw_ostream &OS) {
|
||||
SourceLoc Loc = Range.getStart();
|
||||
unsigned BufID = SM.findBufferContainingLoc(Loc);
|
||||
unsigned Offset = SM.getLocOffsetInBuffer(Loc, BufID);
|
||||
unsigned Length = Range.getByteLength();
|
||||
SmallString<200> Path =
|
||||
StringRef(SM.getIdentifierForBuffer(BufID));
|
||||
|
||||
OS << " {\n";
|
||||
OS << " \"file\": \"";
|
||||
OS.write_escaped(Path.str()) << "\",\n";
|
||||
OS << " \"offset\": " << Offset << ",\n";
|
||||
if (Length != 0)
|
||||
OS << " \"remove\": " << Length << ",\n";
|
||||
if (!Text.empty()) {
|
||||
OS << " \"text\": \"";
|
||||
OS.write_escaped(Text) << "\",\n";
|
||||
}
|
||||
OS << " },\n";
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
int fixit_main(ArrayRef<const char *> Args, const char *Argv0, void *MainAddr){
|
||||
CompilerInstance Instance;
|
||||
PrintingDiagnosticConsumer PDC;
|
||||
Instance.addDiagnosticConsumer(&PDC);
|
||||
|
||||
CompilerInvocation Invocation;
|
||||
std::string MainExecutablePath = llvm::sys::fs::getMainExecutable(Argv0,
|
||||
MainAddr);
|
||||
Invocation.setMainExecutablePath(MainExecutablePath);
|
||||
|
||||
// Parse arguments.
|
||||
if (Invocation.parseArgs(Args, Instance.getDiags())) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
Invocation.getDiagnosticOptions().ShowDiagnosticsAfterFatalError = true;
|
||||
|
||||
std::error_code EC;
|
||||
llvm::raw_fd_ostream OutOS(Invocation.getOutputFilename(), EC, llvm::sys::fs::F_None);
|
||||
|
||||
if (OutOS.has_error() || EC) {
|
||||
Instance.getDiags().diagnose(SourceLoc(), diag::error_opening_output,
|
||||
Invocation.getOutputFilename(), EC.message());
|
||||
OutOS.clear_error();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSONFixitWriter FixWriter(OutOS);
|
||||
FixWriter.addConsumers(Instance.getDiags().takeConsumers());
|
||||
Instance.addDiagnosticConsumer(&FixWriter);
|
||||
|
||||
// TODO: reorder, if possible, so that diagnostics emitted during
|
||||
// CompilerInvocation::parseArgs are included in the serialized file.
|
||||
std::unique_ptr<DiagnosticConsumer> SerializedConsumer;
|
||||
{
|
||||
const std::string &SerializedDiagnosticsPath =
|
||||
Invocation.getFrontendOptions().SerializedDiagnosticsPath;
|
||||
if (!SerializedDiagnosticsPath.empty()) {
|
||||
std::error_code EC;
|
||||
std::unique_ptr<llvm::raw_fd_ostream> OS;
|
||||
OS.reset(new llvm::raw_fd_ostream(SerializedDiagnosticsPath,
|
||||
EC,
|
||||
llvm::sys::fs::F_None));
|
||||
|
||||
if (EC) {
|
||||
Instance.getDiags().diagnose(SourceLoc(),
|
||||
diag::cannot_open_serialized_file,
|
||||
SerializedDiagnosticsPath, EC.message());
|
||||
return 1;
|
||||
}
|
||||
|
||||
SerializedConsumer.reset(
|
||||
serialized_diagnostics::createConsumer(std::move(OS)));
|
||||
FixWriter.addConsumer(SerializedConsumer.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (Invocation.getDiagnosticOptions().UseColor)
|
||||
PDC.forceColors();
|
||||
|
||||
if (Instance.setup(Invocation)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
Instance.performSema();
|
||||
return FixWriter.hasUnfixedError();
|
||||
}
|
||||
@@ -349,6 +349,60 @@ static IRGenOutputKind getOutputKind(FrontendOptions::ActionType Action) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// If there is an error with fixits it writes the fixits as edits in json
|
||||
/// format.
|
||||
class JSONFixitWriter : public DiagnosticConsumer {
|
||||
std::unique_ptr<llvm::raw_ostream> OSPtr;
|
||||
|
||||
public:
|
||||
explicit JSONFixitWriter(std::unique_ptr<llvm::raw_ostream> OS)
|
||||
: OSPtr(std::move(OS)) {
|
||||
*OSPtr << "[\n";
|
||||
}
|
||||
~JSONFixitWriter() {
|
||||
*OSPtr << "]\n";
|
||||
}
|
||||
|
||||
private:
|
||||
void handleDiagnostic(SourceManager &SM, SourceLoc Loc,
|
||||
DiagnosticKind Kind, StringRef Text,
|
||||
const DiagnosticInfo &Info) override {
|
||||
if (Kind != DiagnosticKind::Error)
|
||||
return;
|
||||
if (Info.FixIts.empty())
|
||||
return;
|
||||
for (const auto &Fix : Info.FixIts) {
|
||||
writeEdit(SM, Fix.getRange(), Fix.getText(), *OSPtr);
|
||||
}
|
||||
}
|
||||
|
||||
void writeEdit(SourceManager &SM, CharSourceRange Range, StringRef Text,
|
||||
llvm::raw_ostream &OS) {
|
||||
SourceLoc Loc = Range.getStart();
|
||||
unsigned BufID = SM.findBufferContainingLoc(Loc);
|
||||
unsigned Offset = SM.getLocOffsetInBuffer(Loc, BufID);
|
||||
unsigned Length = Range.getByteLength();
|
||||
SmallString<200> Path =
|
||||
StringRef(SM.getIdentifierForBuffer(BufID));
|
||||
|
||||
OS << " {\n";
|
||||
OS << " \"file\": \"";
|
||||
OS.write_escaped(Path.str()) << "\",\n";
|
||||
OS << " \"offset\": " << Offset << ",\n";
|
||||
if (Length != 0)
|
||||
OS << " \"remove\": " << Length << ",\n";
|
||||
if (!Text.empty()) {
|
||||
OS << " \"text\": \"";
|
||||
OS.write_escaped(Text) << "\",\n";
|
||||
}
|
||||
OS << " },\n";
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/// Performs the compile requested by the user.
|
||||
/// \returns true on error
|
||||
static bool performCompile(CompilerInstance &Instance,
|
||||
@@ -728,6 +782,29 @@ int frontend_main(ArrayRef<const char *>Args,
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<DiagnosticConsumer> FixitsConsumer;
|
||||
{
|
||||
const std::string &FixitsOutputPath =
|
||||
Invocation.getFrontendOptions().FixitsOutputPath;
|
||||
if (!FixitsOutputPath.empty()) {
|
||||
std::error_code EC;
|
||||
std::unique_ptr<llvm::raw_fd_ostream> OS;
|
||||
OS.reset(new llvm::raw_fd_ostream(FixitsOutputPath,
|
||||
EC,
|
||||
llvm::sys::fs::F_None));
|
||||
|
||||
if (EC) {
|
||||
Instance.getDiags().diagnose(SourceLoc(),
|
||||
diag::cannot_open_file,
|
||||
FixitsOutputPath, EC.message());
|
||||
return 1;
|
||||
}
|
||||
|
||||
FixitsConsumer.reset(new JSONFixitWriter(std::move(OS)));
|
||||
Instance.addDiagnosticConsumer(FixitsConsumer.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (Invocation.getDiagnosticOptions().UseColor)
|
||||
PDC.forceColors();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user