kadircet created this revision.
kadircet added a reviewer: ilya-biryukov.
Herald added subscribers: cfe-commits, arphaman, jkorous, MaskRay, ioeric.

Some projects make use of clang plugins when building, but clangd is
not aware of those plugins therefore can't work with the same compile command
arguments.

We invoke clang in two different codepaths one in backgroundindex and
another when building asts. This patch adds the filtering logic to their
intersection.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D56841

Files:
  clangd/ClangdUnit.cpp
  unittests/clangd/ClangdTests.cpp


Index: unittests/clangd/ClangdTests.cpp
===================================================================
--- unittests/clangd/ClangdTests.cpp
+++ unittests/clangd/ClangdTests.cpp
@@ -1037,6 +1037,27 @@
 }
 #endif
 
+TEST_F(ClangdVFSTest, FlagsWithPlugins) {
+  MockFSProvider FS;
+  ErrorCheckingDiagConsumer DiagConsumer;
+  MockCompilationDatabase CDB;
+  CDB.ExtraClangFlags = {
+      "-Xclang",
+      "-add-plugin",
+      "-Xclang",
+      "random-plugin",
+  };
+  ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+  auto FooCpp = testPath("foo.cpp");
+  const auto SourceContents = "int main() { return 0; }";
+  FS.Files[FooCpp] = FooCpp;
+  Server.addDocument(FooCpp, SourceContents);
+  auto Result = dumpASTWithoutMemoryLocs(Server, FooCpp);
+  EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
+  EXPECT_NE(Result, "<no-ast>");
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang
Index: clangd/ClangdUnit.cpp
===================================================================
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -425,8 +425,21 @@
 std::unique_ptr<CompilerInvocation>
 buildCompilerInvocation(const ParseInputs &Inputs) {
   std::vector<const char *> ArgStrs;
-  for (const auto &S : Inputs.CompileCommand.CommandLine)
-    ArgStrs.push_back(S.c_str());
+  const auto &CommandLine = Inputs.CompileCommand.CommandLine;
+  for (size_t I = 0, E = CommandLine.size(); I != E; I++) {
+    // According to https://clang.llvm.org/docs/ClangPlugins.html
+    // -Xclang {-load, -plugin, -plugin-arg-<plugin-name>, -add-plugin} -Xclang
+    // <arbitrary-argument>
+    if (I + 4 < E && CommandLine[I] == "-Xclang" &&
+        (CommandLine[I + 1] == "-load" || CommandLine[I + 1] == "-plugin" ||
+         llvm::StringRef(CommandLine[I + 1]).startswith("-plugin-arg-") ||
+         CommandLine[I + 1] == "-add-plugin") &&
+        CommandLine[I + 2] == "-Xclang") {
+      I += 3;
+      continue;
+    }
+    ArgStrs.push_back(CommandLine[I].c_str());
+  }
 
   if (Inputs.FS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
     log("Couldn't set working directory when creating compiler invocation.");


Index: unittests/clangd/ClangdTests.cpp
===================================================================
--- unittests/clangd/ClangdTests.cpp
+++ unittests/clangd/ClangdTests.cpp
@@ -1037,6 +1037,27 @@
 }
 #endif
 
+TEST_F(ClangdVFSTest, FlagsWithPlugins) {
+  MockFSProvider FS;
+  ErrorCheckingDiagConsumer DiagConsumer;
+  MockCompilationDatabase CDB;
+  CDB.ExtraClangFlags = {
+      "-Xclang",
+      "-add-plugin",
+      "-Xclang",
+      "random-plugin",
+  };
+  ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
+
+  auto FooCpp = testPath("foo.cpp");
+  const auto SourceContents = "int main() { return 0; }";
+  FS.Files[FooCpp] = FooCpp;
+  Server.addDocument(FooCpp, SourceContents);
+  auto Result = dumpASTWithoutMemoryLocs(Server, FooCpp);
+  EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
+  EXPECT_NE(Result, "<no-ast>");
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang
Index: clangd/ClangdUnit.cpp
===================================================================
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -425,8 +425,21 @@
 std::unique_ptr<CompilerInvocation>
 buildCompilerInvocation(const ParseInputs &Inputs) {
   std::vector<const char *> ArgStrs;
-  for (const auto &S : Inputs.CompileCommand.CommandLine)
-    ArgStrs.push_back(S.c_str());
+  const auto &CommandLine = Inputs.CompileCommand.CommandLine;
+  for (size_t I = 0, E = CommandLine.size(); I != E; I++) {
+    // According to https://clang.llvm.org/docs/ClangPlugins.html
+    // -Xclang {-load, -plugin, -plugin-arg-<plugin-name>, -add-plugin} -Xclang
+    // <arbitrary-argument>
+    if (I + 4 < E && CommandLine[I] == "-Xclang" &&
+        (CommandLine[I + 1] == "-load" || CommandLine[I + 1] == "-plugin" ||
+         llvm::StringRef(CommandLine[I + 1]).startswith("-plugin-arg-") ||
+         CommandLine[I + 1] == "-add-plugin") &&
+        CommandLine[I + 2] == "-Xclang") {
+      I += 3;
+      continue;
+    }
+    ArgStrs.push_back(CommandLine[I].c_str());
+  }
 
   if (Inputs.FS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
     log("Couldn't set working directory when creating compiler invocation.");
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to