[clangd] Unify compiler invocation creation

Background-indexing is fine, because it uses GlobalCompilationDatabase
to fetch the compile commands (hence uses CommandMangler), and creates
invocation through buildCompilerInvocation.

Depends on D106639.

Differential Revision: https://reviews.llvm.org/D106669
This commit is contained in:
Kadir Cetinkaya 2021-07-23 16:57:33 +02:00
parent 6569b7f902
commit 41e2422286
No known key found for this signature in database
GPG Key ID: E39E36B8D2057ED6
5 changed files with 69 additions and 41 deletions

View File

@ -26,10 +26,6 @@ namespace clangd {
// - forcing the use of clangd's builtin headers rather than clang's
// - resolving argv0 as cc1 expects
// - injecting -isysroot flags on mac as the system clang does
// FIXME: This is currently not used in all code paths that create invocations.
// Make use of these adjusters and buildCompilerInvocation in clangd-indexer as
// well. It should be possible to hook it up by overriding RunInvocation in
// FrontendActionFactory.
struct CommandMangler {
// Absolute path to clang.
llvm::Optional<std::string> ClangPath;

View File

@ -9,6 +9,7 @@
#include "Compiler.h"
#include "support/Logger.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Serialization/PCHContainerOperations.h"
#include "llvm/ADT/StringRef.h"
@ -41,6 +42,44 @@ void IgnoreDiagnostics::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
IgnoreDiagnostics::log(DiagLevel, Info);
}
void disableUnsupportedOptions(CompilerInvocation &CI) {
// Disable "clang -verify" diagnostics, they are rarely useful in clangd, and
// our compiler invocation set-up doesn't seem to work with it (leading
// assertions in VerifyDiagnosticConsumer).
CI.getDiagnosticOpts().VerifyDiagnostics = false;
CI.getDiagnosticOpts().ShowColors = false;
// Disable any dependency outputting, we don't want to generate files or write
// to stdout/stderr.
CI.getDependencyOutputOpts().ShowIncludesDest = ShowIncludesDestination::None;
CI.getDependencyOutputOpts().OutputFile.clear();
CI.getDependencyOutputOpts().HeaderIncludeOutputFile.clear();
CI.getDependencyOutputOpts().DOTOutputFile.clear();
CI.getDependencyOutputOpts().ModuleDependencyOutputDir.clear();
// Disable any pch generation/usage operations. Since serialized preamble
// format is unstable, using an incompatible one might result in unexpected
// behaviours, including crashes.
CI.getPreprocessorOpts().ImplicitPCHInclude.clear();
CI.getPreprocessorOpts().PrecompiledPreambleBytes = {0, false};
CI.getPreprocessorOpts().PCHThroughHeader.clear();
CI.getPreprocessorOpts().PCHWithHdrStop = false;
CI.getPreprocessorOpts().PCHWithHdrStopCreate = false;
// Don't crash on `#pragma clang __debug parser_crash`
CI.getPreprocessorOpts().DisablePragmaDebugCrash = true;
// Always default to raw container format as clangd doesn't registry any other
// and clang dies when faced with unknown formats.
CI.getHeaderSearchOpts().ModuleFormat =
PCHContainerOperations().getRawReader().getFormat().str();
CI.getFrontendOpts().Plugins.clear();
CI.getFrontendOpts().AddPluginActions.clear();
CI.getFrontendOpts().PluginArgs.clear();
CI.getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
CI.getFrontendOpts().ActionName.clear();
}
std::unique_ptr<CompilerInvocation>
buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D,
std::vector<std::string> *CC1Args) {
@ -60,43 +99,8 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D,
CI->getFrontendOpts().DisableFree = false;
CI->getLangOpts()->CommentOpts.ParseAllComments = true;
CI->getLangOpts()->RetainCommentsFromSystemHeaders = true;
// Disable "clang -verify" diagnostics, they are rarely useful in clangd, and
// our compiler invocation set-up doesn't seem to work with it (leading
// assertions in VerifyDiagnosticConsumer).
CI->getDiagnosticOpts().VerifyDiagnostics = false;
CI->getDiagnosticOpts().ShowColors = false;
// Disable any dependency outputting, we don't want to generate files or write
// to stdout/stderr.
CI->getDependencyOutputOpts().ShowIncludesDest =
ShowIncludesDestination::None;
CI->getDependencyOutputOpts().OutputFile.clear();
CI->getDependencyOutputOpts().HeaderIncludeOutputFile.clear();
CI->getDependencyOutputOpts().DOTOutputFile.clear();
CI->getDependencyOutputOpts().ModuleDependencyOutputDir.clear();
// Disable any pch generation/usage operations. Since serialized preamble
// format is unstable, using an incompatible one might result in unexpected
// behaviours, including crashes.
CI->getPreprocessorOpts().ImplicitPCHInclude.clear();
CI->getPreprocessorOpts().PrecompiledPreambleBytes = {0, false};
CI->getPreprocessorOpts().PCHThroughHeader.clear();
CI->getPreprocessorOpts().PCHWithHdrStop = false;
CI->getPreprocessorOpts().PCHWithHdrStopCreate = false;
// Don't crash on `#pragma clang __debug parser_crash`
CI->getPreprocessorOpts().DisablePragmaDebugCrash = true;
// Always default to raw container format as clangd doesn't registry any other
// and clang dies when faced with unknown formats.
CI->getHeaderSearchOpts().ModuleFormat =
PCHContainerOperations().getRawReader().getFormat().str();
CI->getFrontendOpts().Plugins.clear();
CI->getFrontendOpts().AddPluginActions.clear();
CI->getFrontendOpts().PluginArgs.clear();
CI->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
CI->getFrontendOpts().ActionName.clear();
disableUnsupportedOptions(*CI);
return CI;
}

View File

@ -61,6 +61,12 @@ struct ParseInputs {
FeatureModuleSet *FeatureModules = nullptr;
};
/// Clears \p CI from options that are not supported by clangd, like codegen or
/// plugins. This should be combined with CommandMangler::adjust, which provides
/// similar functionality for options that needs to be stripped from compile
/// flags.
void disableUnsupportedOptions(CompilerInvocation &CI);
/// Builds compiler invocation that could be used to build AST or preamble.
std::unique_ptr<CompilerInvocation>
buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D,

View File

@ -10,6 +10,8 @@
//
//===----------------------------------------------------------------------===//
#include "CompileCommands.h"
#include "Compiler.h"
#include "index/IndexAction.h"
#include "index/Merge.h"
#include "index/Ref.h"
@ -23,6 +25,7 @@
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"
#include <utility>
namespace clang {
namespace clangd {
@ -82,6 +85,15 @@ public:
/*IncludeGraphCallback=*/nullptr);
}
bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
FileManager *Files,
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
DiagnosticConsumer *DiagConsumer) override {
disableUnsupportedOptions(*Invocation);
return tooling::FrontendActionFactory::runInvocation(
std::move(Invocation), Files, std::move(PCHContainerOps), DiagConsumer);
}
// Awkward: we write the result in the destructor, because the executor
// takes ownership so it's the easiest way to get our data back out.
~IndexActionFactory() {
@ -135,7 +147,8 @@ int main(int argc, const char **argv) {
clang::clangd::IndexFileIn Data;
auto Err = Executor->get()->execute(
std::make_unique<clang::clangd::IndexActionFactory>(Data),
clang::tooling::getStripPluginsAdjuster());
clang::tooling::ArgumentsAdjuster(
clang::clangd::CommandMangler::detect()));
if (Err) {
clang::clangd::elog("{0}", std::move(Err));
}

View File

@ -0,0 +1,9 @@
# RUN: rm -rf %t.cpp
# RUN: touch %t.cpp
#
# Make sure compile flags are adjusted for clangd. `--save-temps` creates a
# `.ii` file and `-verify` triggers extra diagnostics generation. Clangd should
# strip those.
# RUN: clangd-indexer %t.cpp -- -Xclang -verify --save-temps -- 2>&1 | FileCheck %s
# CHECK-NOT: error: no expected directives found: consider use of 'expected-no-diagnostics'
# RUN: not ls %t.ii