[CodeCompletion] Make sure callback is always called from performOperation

We had some situations left that neither returned an error, nor called the callback with results in `performOperation`. Return an error in these and adjust the tests to correctly match the error.
This commit is contained in:
Alex Hoppen
2021-10-07 19:04:56 +02:00
parent 2fcb24e716
commit b6e03e3d98
8 changed files with 89 additions and 36 deletions

View File

@@ -866,28 +866,48 @@ static bool doCodeCompletionImpl(
PrintingDiagnosticConsumer PrintDiags;
CompletionInstance CompletionInst;
// FIXME: Should we count it as an error if we didn't receive a callback?
bool HadError = false;
std::string CompletionError;
bool CallbackCalled = false;
CompletionInst.performOperation(
Invocation, /*Args=*/{}, llvm::vfs::getRealFileSystem(), CleanFile.get(),
Offset, CodeCompletionDiagnostics ? &PrintDiags : nullptr,
[&](CancellableResult<CompletionInstanceResult> Result) {
CallbackCalled = true;
switch (Result.getKind()) {
case CancellableResultKind::Success: {
HadError = false;
assert(!Result->DidReuseAST &&
"reusing AST context without enabling it");
if (!Result->DidFindCodeCompletionToken) {
// Return empty results by not performing the second pass and never
// calling the consumer of the callback factory.
return;
}
performCodeCompletionSecondPass(*Result->CI.getCodeCompletionFile(),
*callbacksFactory);
break;
}
case CancellableResultKind::Failure:
CompletionError = "error: " + Result.getError();
break;
case CancellableResultKind::Cancelled:
HadError = true;
CompletionError = "request cancelled";
break;
}
});
return HadError;
assert(CallbackCalled &&
"We should always receive a callback call for code completion");
if (CompletionError == "error: did not find code completion token") {
// Do not consider failure to find the code completion token as a critical
// failure that returns a non-zero exit code. Instead, allow the caller to
// match the error message.
llvm::outs() << CompletionError << '\n';
} else if (!CompletionError.empty()) {
llvm::errs() << CompletionError << '\n';
return true;
}
return false;
}
static int doTypeContextInfo(const CompilerInvocation &InitInvok,
@@ -1279,16 +1299,20 @@ static int doBatchCodeCompletion(const CompilerInvocation &InitInvok,
PrintingDiagnosticConsumer PrintDiags;
auto completionStart = std::chrono::high_resolution_clock::now();
bool wasASTContextReused = false;
// FIXME: Should we count it as an error if we didn't receive a callback?
bool completionDidFail = false;
std::string completionError = "";
bool CallbackCalled = false;
CompletionInst.performOperation(
Invocation, /*Args=*/{}, FileSystem, completionBuffer.get(), Offset,
CodeCompletionDiagnostics ? &PrintDiags : nullptr,
[&](CancellableResult<CompletionInstanceResult> Result) {
CallbackCalled = true;
switch (Result.getKind()) {
case CancellableResultKind::Success: {
completionDidFail = false;
if (!Result->DidFindCodeCompletionToken) {
// Return empty results by not performing the second pass and
// never calling the consumer of the callback factory.
return;
}
wasASTContextReused = Result->DidReuseAST;
// Create a CodeCompletionConsumer.
@@ -1314,15 +1338,15 @@ static int doBatchCodeCompletion(const CompilerInvocation &InitInvok,
break;
}
case CancellableResultKind::Failure:
completionDidFail = true;
llvm::errs() << "error: " << Result.getError() << "\n";
completionError = "error: " + Result.getError();
break;
case CancellableResultKind::Cancelled:
completionDidFail = true;
llvm::errs() << "request cancelled\n";
completionError = "request cancelled";
break;
}
});
assert(CallbackCalled &&
"We should always receive a callback call for code completion");
auto completionEnd = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
completionEnd - completionStart);
@@ -1350,13 +1374,18 @@ static int doBatchCodeCompletion(const CompilerInvocation &InitInvok,
}
llvm::raw_fd_ostream fileOut(resultFD, /*shouldClose=*/true);
fileOut << ResultStr;
fileOut.close();
if (completionDidFail) {
// error message was already emitted above.
if (completionError == "error: did not find code completion token") {
// Do not consider failure to find the code completion token as a critical
// failure that returns a non-zero exit code. Instead, allow the caller to
// match the error message.
fileOut << completionError;
} else if (!completionError.empty()) {
llvm::errs() << completionError << '\n';
return 1;
} else {
fileOut << ResultStr;
}
fileOut.close();
if (options::SkipFileCheck)
continue;