Skip to content

Commit 44f8e19

Browse files
committed
[SourceKit] Recover if compiler arguments have errors
If the compiler arguments have errors in them (e.g. because a file with the same name is used twice), we can often still fulfill SourceKit requests because the compiler argument errors are only relevant for later stages of the compilation process. Instead of bailing out early, do a best effor retrieving the compiler arguments that are valid and ignoring the errors. Fixes rdar://77618144
1 parent e8c6ac0 commit 44f8e19

File tree

8 files changed

+51
-21
lines changed

8 files changed

+51
-21
lines changed

include/swift/Driver/Driver.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,17 @@ class Driver {
262262
/// Construct a compilation object for a given ToolChain and command line
263263
/// argument vector.
264264
///
265+
/// If \p AllowErrors is set to \c true, this method tries to build a
266+
/// compilation even if there were errors.
267+
///
265268
/// \return A Compilation, or nullptr if none was built for the given argument
266269
/// vector. A null return value does not necessarily indicate an error
267270
/// condition; the diagnostics should be queried to determine if an error
268271
/// occurred.
269272
std::unique_ptr<Compilation>
270273
buildCompilation(const ToolChain &TC,
271-
std::unique_ptr<llvm::opt::InputArgList> ArgList);
274+
std::unique_ptr<llvm::opt::InputArgList> ArgList,
275+
bool AllowErrors = false);
272276

273277
/// Parse the given list of strings into an InputArgList.
274278
std::unique_ptr<llvm::opt::InputArgList>

lib/Driver/Driver.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,8 @@ getDriverBatchSizeLimit(llvm::opt::InputArgList &ArgList,
860860

861861
std::unique_ptr<Compilation>
862862
Driver::buildCompilation(const ToolChain &TC,
863-
std::unique_ptr<llvm::opt::InputArgList> ArgList) {
863+
std::unique_ptr<llvm::opt::InputArgList> ArgList,
864+
bool AllowErrors) {
864865
llvm::PrettyStackTraceString CrashInfo("Compilation construction");
865866

866867
llvm::sys::TimePoint<> StartTime = std::chrono::system_clock::now();
@@ -880,7 +881,7 @@ Driver::buildCompilation(const ToolChain &TC,
880881
// Perform toolchain specific args validation.
881882
TC.validateArguments(Diags, *TranslatedArgList, DefaultTargetTriple);
882883

883-
if (Diags.hadAnyError())
884+
if (Diags.hadAnyError() && !AllowErrors)
884885
return nullptr;
885886

886887
if (!handleImmediateArgs(*TranslatedArgList, TC)) {
@@ -891,7 +892,7 @@ Driver::buildCompilation(const ToolChain &TC,
891892
InputFileList Inputs;
892893
buildInputs(TC, *TranslatedArgList, Inputs);
893894

894-
if (Diags.hadAnyError())
895+
if (Diags.hadAnyError() && !AllowErrors)
895896
return nullptr;
896897

897898
// Determine the OutputInfo for the driver.
@@ -900,14 +901,14 @@ Driver::buildCompilation(const ToolChain &TC,
900901
OI.CompilerMode = computeCompilerMode(*TranslatedArgList, Inputs, BatchMode);
901902
buildOutputInfo(TC, *TranslatedArgList, BatchMode, Inputs, OI);
902903

903-
if (Diags.hadAnyError())
904+
if (Diags.hadAnyError() && !AllowErrors)
904905
return nullptr;
905906

906907
assert(OI.CompilerOutputType != file_types::ID::TY_INVALID &&
907908
"buildOutputInfo() must set a valid output type!");
908909

909910
TC.validateOutputInfo(Diags, OI);
910-
if (Diags.hadAnyError())
911+
if (Diags.hadAnyError() && !AllowErrors)
911912
return nullptr;
912913

913914
validateEmbedBitcode(*TranslatedArgList, OI, Diags);
@@ -919,15 +920,17 @@ Driver::buildCompilation(const ToolChain &TC,
919920
Optional<OutputFileMap> OFM = buildOutputFileMap(
920921
*TranslatedArgList, workingDirectory);
921922

922-
if (Diags.hadAnyError())
923+
if (Diags.hadAnyError() && !AllowErrors)
923924
return nullptr;
924925

925926
if (ArgList->hasArg(options::OPT_driver_print_output_file_map)) {
926927
if (OFM)
927928
OFM->dump(llvm::errs(), true);
928929
else
929930
Diags.diagnose(SourceLoc(), diag::error_no_output_file_map_specified);
930-
return nullptr;
931+
if (!AllowErrors) {
932+
return nullptr;
933+
}
931934
}
932935

933936
const bool ShowIncrementalBuildDecisions =
@@ -1044,7 +1047,7 @@ Driver::buildCompilation(const ToolChain &TC,
10441047
buildActions(TopLevelActions, TC, OI,
10451048
whyIgnoreIncrementallity.empty() ? &outOfDateMap : nullptr, *C);
10461049

1047-
if (Diags.hadAnyError())
1050+
if (Diags.hadAnyError() && !AllowErrors)
10481051
return nullptr;
10491052

10501053
if (DriverPrintActions) {
@@ -1076,7 +1079,7 @@ Driver::buildCompilation(const ToolChain &TC,
10761079
if (!whyIgnoreIncrementallity.empty())
10771080
C->disableIncrementalBuild(whyIgnoreIncrementallity);
10781081

1079-
if (Diags.hadAnyError())
1082+
if (Diags.hadAnyError() && !AllowErrors)
10801083
return nullptr;
10811084

10821085
if (DriverPrintBindings)

lib/Driver/FrontendUtil.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ bool swift::driver::getSingleFrontendInvocationFromDriverArguments(
101101
return true;
102102

103103
std::unique_ptr<Compilation> C =
104-
TheDriver.buildCompilation(*TC, std::move(ArgList));
104+
TheDriver.buildCompilation(*TC, std::move(ArgList), /*AllowErrors=*/true);
105105
if (!C || C->getJobs().empty())
106106
return true; // Don't emit an error; one should already have been emitted
107107

@@ -113,7 +113,6 @@ bool swift::driver::getSingleFrontendInvocationFromDriverArguments(
113113
if (CompileCommands.size() != 1) {
114114
// TODO: include Jobs in the diagnostic.
115115
Diags.diagnose(SourceLoc(), diag::error_expected_one_frontend_job);
116-
return true;
117116
}
118117

119118
const Job *Cmd = *CompileCommands.begin();

lib/IDE/Utils.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -294,30 +294,38 @@ bool ide::initCompilerInvocation(
294294
StreamDiagConsumer DiagConsumer(ErrOS);
295295
Diags.addConsumer(DiagConsumer);
296296

297-
bool HadError = driver::getSingleFrontendInvocationFromDriverArguments(
298-
Args, Diags, [&](ArrayRef<const char *> FrontendArgs) {
299-
return Invocation.parseArgs(FrontendArgs, Diags);
300-
}, /*ForceNoOutputs=*/true);
297+
bool InvocationCreationFailed =
298+
driver::getSingleFrontendInvocationFromDriverArguments(
299+
Args, Diags,
300+
[&](ArrayRef<const char *> FrontendArgs) {
301+
return Invocation.parseArgs(FrontendArgs, Diags);
302+
},
303+
/*ForceNoOutputs=*/true);
301304

302305
// Remove the StreamDiagConsumer as it's no longer needed.
303306
Diags.removeConsumer(DiagConsumer);
304307

305-
if (HadError) {
306-
Error = std::string(ErrOS.str());
308+
Error = std::string(ErrOS.str());
309+
if (InvocationCreationFailed) {
307310
return true;
308311
}
309312

313+
std::string SymlinkResolveError;
310314
Invocation.getFrontendOptions().InputsAndOutputs =
311315
resolveSymbolicLinksInInputs(
312316
Invocation.getFrontendOptions().InputsAndOutputs,
313-
UnresolvedPrimaryFile, FileSystem, Error);
317+
UnresolvedPrimaryFile, FileSystem, SymlinkResolveError);
314318

315319
// SourceKit functionalities want to proceed even if there are missing inputs.
316320
Invocation.getFrontendOptions().InputsAndOutputs
317321
.setShouldRecoverMissingInputs();
318322

319-
if (!Error.empty())
323+
if (!SymlinkResolveError.empty()) {
324+
// resolveSymbolicLinksInInputs fails if the unresolved primary file is not
325+
// in the input files. We can't recover from that.
326+
Error += SymlinkResolveError;
320327
return true;
328+
}
321329

322330
ClangImporterOptions &ImporterOpts = Invocation.getClangImporterOptions();
323331
ImporterOpts.DetailedPreprocessingRecord = true;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class Foo {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class Bar {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// We should not fail if two distinct file have the same name - this is only an issue in CodeGen
2+
// RUN: %sourcekitd-test -req=cursor -pos=1:7 %S/Inputs/invalid_compiler_args/A/File.swift -- %S/Inputs/invalid_compiler_args/A/File.swift %S/Inputs/invalid_compiler_args/B/File.swift | %FileCheck %s
3+
4+
// We can't do anything if the requested file is not in the compiler arguments
5+
// RUN: not %sourcekitd-test -req=cursor -pos=1:7 %S/Inputs/invalid_compiler_args/A/File.swift --
6+
// RUN: not %sourcekitd-test -req=cursor -pos=1:7 %S/Inputs/invalid_compiler_args/A/File.swift -- %S/Inputs/invalid_compiler_args/B/File.swift
7+
8+
// Specifying a file twice should just ignore one of them
9+
// RUN: %sourcekitd-test -req=cursor -pos=1:7 %S/Inputs/invalid_compiler_args/A/File.swift -- %S/Inputs/invalid_compiler_args/A/File.swift %S/Inputs/invalid_compiler_args/A/File.swift
10+
11+
12+
// CHECK: source.lang.swift.decl.class

tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1788,8 +1788,10 @@ void SwiftLangSupport::getCursorInfo(
17881788
std::string Error;
17891789
SwiftInvocationRef Invok =
17901790
ASTMgr->getInvocation(Args, InputFile, fileSystem, Error);
1791+
if (!Error.empty()) {
1792+
LOG_WARN_FUNC("error creating ASTInvocation: " << Error);
1793+
}
17911794
if (!Invok) {
1792-
LOG_WARN_FUNC("failed to create an ASTInvocation: " << Error);
17931795
Receiver(RequestResult<CursorInfoData>::fromError(Error));
17941796
return;
17951797
}

0 commit comments

Comments
 (0)