Sam McCall 04b4190489 [Driver] Make "upgrade" of -include to include-pch optional; disable in clangd
If clang is passed "-include foo.h", it will rewrite to "-include-pch foo.h.pch"
before passing it to cc1, if foo.h.pch exists.

Existence is checked, but validity is not. This is probably a reasonable
assumption for the compiler itself, but not for clang-based tools where the
actual compiler may be a different version of clang, or even GCC.
In the end, we lose our -include, we gain a -include-pch that can't be used,
and the file often fails to parse.

I would like to turn this off for all non-clang invocations (i.e.
createInvocationFromCommandLine), but we have explicit tests of this behavior
for libclang and I can't work out the implications of changing it.

Instead this patch:
 - makes it optional in the driver, default on (no change)
 - makes it optional in createInvocationFromCommandLine, default on (no change)
 - changes driver to do IO through the VFS so it can be tested
 - tests the option
 - turns the option off in clangd where the problem was reported

Subsequent patches should make libclang opt in explicitly and flip the default
for all other tools. It's probably also time to extract an options struct
for createInvocationFromCommandLine.

Fixes https://github.com/clangd/clangd/issues/856
Fixes https://github.com/clangd/vscode-clangd/issues/324

Differential Revision: https://reviews.llvm.org/D124970
2022-05-05 16:47:17 +02:00

67 lines
2.9 KiB
C++

//===- unittests/Frontend/UtilsTest.cpp -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "clang/Frontend/Utils.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace clang {
namespace {
using testing::ElementsAre;
TEST(BuildCompilerInvocationTest, RecoverMultipleJobs) {
// This generates multiple jobs and we recover by using the first.
std::vector<const char *> Args = {"clang", "--target=macho", "-arch", "i386",
"-arch", "x86_64", "foo.cpp"};
clang::IgnoringDiagConsumer D;
CreateInvocationOptions Opts;
Opts.RecoverOnError = true;
Opts.Diags = clang::CompilerInstance::createDiagnostics(new DiagnosticOptions,
&D, false);
Opts.VFS = new llvm::vfs::InMemoryFileSystem();
std::unique_ptr<CompilerInvocation> CI = createInvocation(Args, Opts);
ASSERT_TRUE(CI);
EXPECT_THAT(CI->TargetOpts->Triple, testing::StartsWith("i386-"));
}
// buildInvocationFromCommandLine should not translate -include to -include-pch,
// even if the PCH file exists.
TEST(BuildCompilerInvocationTest, ProbePrecompiled) {
std::vector<const char *> Args = {"clang", "-include", "foo.h", "foo.cpp"};
auto FS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
FS->addFile("foo.h", 0, llvm::MemoryBuffer::getMemBuffer(""));
FS->addFile("foo.h.pch", 0, llvm::MemoryBuffer::getMemBuffer(""));
clang::IgnoringDiagConsumer D;
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
clang::CompilerInstance::createDiagnostics(new DiagnosticOptions, &D,
false);
// Default: ProbePrecompiled is true.
std::unique_ptr<CompilerInvocation> CI = createInvocationFromCommandLine(
Args, CommandLineDiagsEngine, FS, false, nullptr);
ASSERT_TRUE(CI);
EXPECT_THAT(CI->getPreprocessorOpts().Includes, ElementsAre());
EXPECT_EQ(CI->getPreprocessorOpts().ImplicitPCHInclude, "foo.h.pch");
CI = createInvocationFromCommandLine(Args, CommandLineDiagsEngine, FS, false,
nullptr, /*ProbePrecompiled=*/false);
ASSERT_TRUE(CI);
EXPECT_THAT(CI->getPreprocessorOpts().Includes, ElementsAre("foo.h"));
EXPECT_EQ(CI->getPreprocessorOpts().ImplicitPCHInclude, "");
}
} // namespace
} // namespace clang