Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion include/swift/Frontend/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,9 @@ class CompilerInstance {
/// Return the buffer ID if it is not already compiled, or None if so.
/// Set failed on failure.

Optional<unsigned> getRecordedBufferID(const InputFile &input, bool &failed);
Optional<unsigned> getRecordedBufferID(const InputFile &input,
const bool shouldRecover,
bool &failed);

/// Given an input file, return a buffer to use for its contents,
/// and a buffer for the corresponding module doc file if one exists.
Expand Down
6 changes: 6 additions & 0 deletions include/swift/Frontend/FrontendInputsAndOutputs.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class FrontendInputsAndOutputs {
/// Punt where needed to enable batch mode experiments.
bool AreBatchModeChecksBypassed = false;

/// Recover missing inputs. Note that recovery itself is users responsibility.
bool ShouldRecoverMissingInputs = false;

public:
bool areBatchModeChecksBypassed() const { return AreBatchModeChecksBypassed; }
void setBypassBatchModeChecks(bool bbc) { AreBatchModeChecksBypassed = bbc; }
Expand All @@ -66,6 +69,9 @@ class FrontendInputsAndOutputs {

bool isWholeModule() const { return !hasPrimaryInputs(); }

bool shouldRecoverMissingInputs() { return ShouldRecoverMissingInputs; }
void setShouldRecoverMissingInputs() { ShouldRecoverMissingInputs = true; }

// Readers:

// All inputs:
Expand Down
24 changes: 19 additions & 5 deletions lib/Frontend/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -599,17 +599,23 @@ bool CompilerInstance::setUpInputs() {

const auto &Inputs =
Invocation.getFrontendOptions().InputsAndOutputs.getAllInputs();
const bool shouldRecover = Invocation.getFrontendOptions()
.InputsAndOutputs.shouldRecoverMissingInputs();

bool hasFailed = false;
for (const InputFile &input : Inputs) {
bool failed = false;
Optional<unsigned> bufferID = getRecordedBufferID(input, failed);
if (failed)
return true;
Optional<unsigned> bufferID =
getRecordedBufferID(input, shouldRecover, failed);
hasFailed |= failed;

if (!bufferID.hasValue() || !input.isPrimary())
continue;

recordPrimaryInputBuffer(*bufferID);
}
if (hasFailed)
return true;

// Set the primary file to the code-completion point if one exists.
if (codeCompletionBufferID.hasValue() &&
Expand All @@ -621,8 +627,9 @@ bool CompilerInstance::setUpInputs() {
return false;
}

Optional<unsigned> CompilerInstance::getRecordedBufferID(const InputFile &input,
bool &failed) {
Optional<unsigned>
CompilerInstance::getRecordedBufferID(const InputFile &input,
const bool shouldRecover, bool &failed) {
if (!input.getBuffer()) {
if (Optional<unsigned> existingBufferID =
SourceMgr.getIDForBufferIdentifier(input.getFileName())) {
Expand All @@ -631,6 +638,13 @@ Optional<unsigned> CompilerInstance::getRecordedBufferID(const InputFile &input,
}
auto buffers = getInputBuffersIfPresent(input);

// Recover by dummy buffer if requested.
if (!buffers.hasValue() && shouldRecover &&
input.getType() == file_types::TY_Swift && !input.isPrimary()) {
buffers = ModuleBuffers(llvm::MemoryBuffer::getMemBuffer(
"// missing file\n", input.getFileName()));
}

if (!buffers.hasValue()) {
failed = true;
return None;
Expand Down
2 changes: 2 additions & 0 deletions lib/Frontend/FrontendInputsAndOutputs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ FrontendInputsAndOutputs::FrontendInputsAndOutputs(
for (InputFile input : other.AllInputs)
addInput(input);
IsSingleThreadedWMO = other.IsSingleThreadedWMO;
ShouldRecoverMissingInputs = other.ShouldRecoverMissingInputs;
}

FrontendInputsAndOutputs &FrontendInputsAndOutputs::
Expand All @@ -46,6 +47,7 @@ operator=(const FrontendInputsAndOutputs &other) {
for (InputFile input : other.AllInputs)
addInput(input);
IsSingleThreadedWMO = other.IsSingleThreadedWMO;
ShouldRecoverMissingInputs = other.ShouldRecoverMissingInputs;
return *this;
}

Expand Down
6 changes: 6 additions & 0 deletions lib/IDE/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ static FrontendInputsAndOutputs resolveSymbolicLinksInInputs(
++primaryCount;
}
assert(primaryCount < 2 && "cannot handle multiple primaries");

replacementInputsAndOutputs.addInput(
InputFile(newFilename.str(), newIsPrimary, input.getBuffer()));
}
Expand Down Expand Up @@ -310,6 +311,11 @@ bool ide::initCompilerInvocation(
resolveSymbolicLinksInInputs(
Invocation.getFrontendOptions().InputsAndOutputs,
UnresolvedPrimaryFile, FileSystem, Error);

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

if (!Error.empty())
return true;

Expand Down
17 changes: 17 additions & 0 deletions test/Frontend/missing_files.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// RUN: %empty-directory(%t)

// RUN: not %target-swift-frontend -c -parse-as-library /tmp/SOMETHING_DOES_NOT_EXIST_1.swift -primary-file %s /tmp/SOMETHING_DOES_NOT_EXIST_2.swift -o %t/out.o 2> %t/error1.output
// RUN: not test -f %t/out.o
// RUN: %FileCheck %s -input-file %t/error1.output --check-prefixes=CHECK

// RUN: not %target-swift-frontend -c -parse-as-library -primary-file /tmp/SOMETHING_DOES_NOT_EXIST_1.swift -primary-file %s /tmp/SOMETHING_DOES_NOT_EXIST_2.swift -o %t/out1.o -o %t/out2.o 2> %t/error2.output
// RUN: not test -f %t/out1.o
// RUN: not test -f %t/out2.o
// RUN: %FileCheck %s -input-file %t/error2.output --check-prefixes=CHECK

// CHECK-DAG: <unknown>:0: error: error opening input file '{{[/\\]}}tmp{{[/\\]}}SOMETHING_DOES_NOT_EXIST_1.swift' ({{.*}})
// CHECK-DAG: <unknown>:0: error: error opening input file '{{[/\\]}}tmp{{[/\\]}}SOMETHING_DOES_NOT_EXIST_2.swift' ({{.*}})

public var x = INVALID_DECL
// CHECK-NOT: INVALID_DECL

3 changes: 3 additions & 0 deletions test/SourceKit/CodeComplete/complete_missing_files.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// RUN: %sourcekitd-test -req=complete -pos=1:1 %s -- /tmp/SOMETHING_DOES_NOT_EXIST_1.swift %s /tmp/SOMETHING_DOES_NOT_EXIST_2.swift | %FileCheck %s

// CHECK: results: [