[clangd] Filter pch related flags coming from the user
authorKadir Cetinkaya <kadircet@google.com>
Sat, 9 May 2020 10:34:06 +0000 (12:34 +0200)
committerKadir Cetinkaya <kadircet@google.com>
Sun, 10 May 2020 11:03:59 +0000 (13:03 +0200)
Summary:
PCH format is unstable, hence using a preamble built with a different
version of clang (or even worse, a different compiler) might result in
unexpected behaviour.

PCH creation on the other hand is something clangd wouldn't want to perform, as
it doesn't generate any output files.

This patch makes sure clangd drops any PCH related compile commands after
parsing the command line args.

Fixes https://github.com/clangd/clangd/issues/248

Reviewers: sammccall

Subscribers: mgorny, ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D79669

clang-tools-extra/clangd/Compiler.cpp
clang-tools-extra/clangd/unittests/CMakeLists.txt
clang-tools-extra/clangd/unittests/CompilerTests.cpp [new file with mode: 0644]

index 957d7c3..04d48b0 100644 (file)
@@ -41,8 +41,7 @@ void IgnoreDiagnostics::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
 }
 
 std::unique_ptr<CompilerInvocation>
-buildCompilerInvocation(const ParseInputs &Inputs,
-                        clang::DiagnosticConsumer &D,
+buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D,
                         std::vector<std::string> *CC1Args) {
   std::vector<const char *> ArgStrs;
   for (const auto &S : Inputs.CompileCommand.CommandLine)
@@ -74,6 +73,15 @@ buildCompilerInvocation(const ParseInputs &Inputs,
   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;
   return CI;
 }
 
index cccb3ce..a1f6af6 100644 (file)
@@ -34,6 +34,7 @@ add_unittest(ClangdUnitTests ClangdTests
   CodeCompletionStringsTests.cpp
   CollectMacrosTests.cpp
   CompileCommandsTests.cpp
+  CompilerTests.cpp
   DexTests.cpp
   DiagnosticsTests.cpp
   DraftStoreTests.cpp
diff --git a/clang-tools-extra/clangd/unittests/CompilerTests.cpp b/clang-tools-extra/clangd/unittests/CompilerTests.cpp
new file mode 100644 (file)
index 0000000..a12a7b9
--- /dev/null
@@ -0,0 +1,55 @@
+//===-- CompilerTests.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 "Compiler.h"
+#include "TestTU.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+using testing::IsEmpty;
+
+TEST(BuildCompilerInvocation, DropsPCH) {
+  IgnoreDiagnostics Diags;
+  TestTU TU;
+  TU.AdditionalFiles["test.h.pch"] = "";
+
+  TU.ExtraArgs = {"-include-pch", "test.h.pch"};
+  EXPECT_THAT(buildCompilerInvocation(TU.inputs(), Diags)
+                  ->getPreprocessorOpts()
+                  .ImplicitPCHInclude,
+              IsEmpty());
+
+  // Transparent include translation
+  TU.ExtraArgs = {"-include", "test.h"};
+  EXPECT_THAT(buildCompilerInvocation(TU.inputs(), Diags)
+                  ->getPreprocessorOpts()
+                  .ImplicitPCHInclude,
+              IsEmpty());
+
+  // CL mode parsing.
+  TU.AdditionalFiles["test.pch"] = "";
+  TU.ExtraArgs = {"--driver-mode=cl"};
+  TU.ExtraArgs.push_back("/Yutest.h");
+  EXPECT_THAT(buildCompilerInvocation(TU.inputs(), Diags)
+                  ->getPreprocessorOpts()
+                  .ImplicitPCHInclude,
+              IsEmpty());
+  EXPECT_THAT(buildCompilerInvocation(TU.inputs(), Diags)
+                  ->getPreprocessorOpts()
+                  .PCHThroughHeader,
+              IsEmpty());
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang