ChuanqiXu updated this revision to Diff 479168.
ChuanqiXu added a comment.

Address comments. Parse flags after "--" as the command line argument for 
compilation database.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137534/new/

https://reviews.llvm.org/D137534

Files:
  clang/include/clang/Tooling/CompilationDatabase.h
  clang/lib/Tooling/CompilationDatabase.cpp
  clang/test/ClangScanDeps/P1689.cppm
  clang/tools/clang-scan-deps/ClangScanDeps.cpp
  clang/unittests/Tooling/CompilationDatabaseTest.cpp

Index: clang/unittests/Tooling/CompilationDatabaseTest.cpp
===================================================================
--- clang/unittests/Tooling/CompilationDatabaseTest.cpp
+++ clang/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -559,7 +559,7 @@
   CommandLine.push_back("two");
   FixedCompilationDatabase Database(".", CommandLine);
 
-  EXPECT_EQ(0ul, Database.getAllCompileCommands().size());
+  EXPECT_EQ(1ul, Database.getAllCompileCommands().size());
 }
 
 TEST(FixedCompilationDatabase, FromBuffer) {
Index: clang/tools/clang-scan-deps/ClangScanDeps.cpp
===================================================================
--- clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -167,7 +167,7 @@
 
 llvm::cl::opt<std::string>
     CompilationDB("compilation-database",
-                  llvm::cl::desc("Compilation database"), llvm::cl::Required,
+                  llvm::cl::desc("Compilation database"), llvm::cl::Optional,
                   llvm::cl::cat(DependencyScannerCategory));
 
 llvm::cl::opt<std::string> ModuleName(
@@ -175,6 +175,23 @@
     llvm::cl::desc("the module of which the dependencies are to be computed"),
     llvm::cl::cat(DependencyScannerCategory));
 
+llvm::cl::opt<std::string> P1689TargetedFileName(
+    "p1689-targeted-file-name", llvm::cl::Optional,
+    llvm::cl::desc("Only supported for P1689, the targeted file name of which "
+                   "the dependencies are to be computed."),
+    llvm::cl::cat(DependencyScannerCategory));
+
+llvm::cl::opt<std::string> P1689TargetedOutput(
+    "p1689-targeted-output", llvm::cl::Optional,
+    llvm::cl::desc("Only supported for P1689, the targeted output of which the "
+                   "dependencies are to be computed."),
+    llvm::cl::cat(DependencyScannerCategory));
+
+llvm::cl::opt<std::string> P1689TargettedCommand(
+    llvm::cl::Positional, llvm::cl::ZeroOrMore,
+    llvm::cl::desc("The command line flags for the target of which "
+                   "the dependencies are to be computed."));
+
 llvm::cl::list<std::string> ModuleDepTargets(
     "dependency-target",
     llvm::cl::desc("The names of dependency targets for the dependency file"),
@@ -522,19 +539,57 @@
   return std::string(Path);
 }
 
-int main(int argc, const char **argv) {
+// getCompilationDataBase - If -compilation-database is set, load the
+// compilation database from the specified file. Otherwise if the we're
+// generating P1689 format, trying to generate the compilation database
+// form the p1689 related command lines. Otherwise, the invocation is
+// ill-formed.
+static std::unique_ptr<tooling::CompilationDatabase>
+getCompilationDataBase(int argc, const char **argv, std::string &ErrorMessage) {
   llvm::InitLLVM X(argc, argv);
   llvm::cl::HideUnrelatedOptions(DependencyScannerCategory);
   if (!llvm::cl::ParseCommandLineOptions(argc, argv))
-    return 1;
+    return nullptr;
+
+  if (!CompilationDB.empty())
+    return tooling::JSONCompilationDatabase::loadFromFile(
+        CompilationDB, ErrorMessage,
+        tooling::JSONCommandLineSyntax::AutoDetect);
+
+  if (Format != ScanningOutputFormat::P1689) {
+    llvm::errs() << "the --compilation-database option: must be specified at "
+                    "least once!";
+    return nullptr;
+  }
+
+  if (P1689TargetedFileName.empty() || P1689TargetedOutput.empty()) {
+    llvm::errs()
+        << "missing compilation database and failed to contruct "
+           "one by --p1689-targeted-file-name, --p1689-targeted-output";
+    return nullptr;
+  }
 
+  // Use FixedCompilationDatabase to parse the command line flags after "--".
+  std::unique_ptr<tooling::FixedCompilationDatabase> FixedCompilationDatabase =
+      tooling::FixedCompilationDatabase::loadFromCommandLine(
+          argc, argv, ErrorMessage,
+          /*Directory=*/".", P1689TargetedFileName, P1689TargetedOutput);
+
+  if (!FixedCompilationDatabase) {
+    llvm::errs()
+        << "We need to pass the command line args after \"--\" marker.";
+    return nullptr;
+  }
+
+  return std::move(FixedCompilationDatabase);
+}
+
+int main(int argc, const char **argv) {
   std::string ErrorMessage;
-  std::unique_ptr<tooling::JSONCompilationDatabase> Compilations =
-      tooling::JSONCompilationDatabase::loadFromFile(
-          CompilationDB, ErrorMessage,
-          tooling::JSONCommandLineSyntax::AutoDetect);
+  std::unique_ptr<tooling::CompilationDatabase> Compilations =
+      getCompilationDataBase(argc, argv, ErrorMessage);
   if (!Compilations) {
-    llvm::errs() << "error: " << ErrorMessage << "\n";
+    llvm::errs() << ErrorMessage << "\n";
     return 1;
   }
 
Index: clang/test/ClangScanDeps/P1689.cppm
===================================================================
--- clang/test/ClangScanDeps/P1689.cppm
+++ clang/test/ClangScanDeps/P1689.cppm
@@ -3,8 +3,25 @@
 // RUN: split-file %s %t
 //
 // RUN: sed "s|DIR|%/t|g" %t/P1689.json.in > %t/P1689.json
-// RUN: clang-scan-deps -compilation-database %t/P1689.json -format=p1689 | FileCheck %t/Checks.cpp -DPREFIX=%/t
-// RUN: clang-scan-deps --mode=preprocess-dependency-directives -compilation-database %t/P1689.json -format=p1689 | FileCheck %t/Checks.cpp -DPREFIX=%/t
+// RUN: clang-scan-deps --compilation-database %t/P1689.json -format=p1689 | FileCheck %t/Checks.cpp -DPREFIX=%/t
+// RUN: clang-scan-deps --mode=preprocess-dependency-directives --compilation-database %t/P1689.json -format=p1689 | FileCheck %t/Checks.cpp -DPREFIX=%/t
+//
+// Check the seperated dependency format.
+// RUN: clang-scan-deps -format=p1689 --p1689-targeted-file-name=%t/M.cppm --p1689-targeted-output=%t/M.o \
+// RUN:   -- -std=c++20 -c \
+// RUN:   | FileCheck %t/M.cppm -DPREFIX=%/t
+// RUN: clang-scan-deps -format=p1689 --p1689-targeted-file-name=%t/Impl.cpp --p1689-targeted-output=%t/Impl.o \
+// RUN:   -- -std=c++20 -c \
+// RUN:   | FileCheck %t/Impl.cpp -DPREFIX=%/t
+// RUN: clang-scan-deps -format=p1689 --p1689-targeted-file-name=%t/impl_part.cppm --p1689-targeted-output=%t/impl_part.o \
+// RUN:   -- -std=c++20 -c \
+// RUN:   | FileCheck %t/impl_part.cppm -DPREFIX=%/t
+// RUN: clang-scan-deps -format=p1689 --p1689-targeted-file-name=%t/interface_part.cppm --p1689-targeted-output=%t/interface_part.o \
+// RUN:   -- -std=c++20 -c \
+// RUN:   | FileCheck %t/interface_part.cppm -DPREFIX=%/t
+// RUN: clang-scan-deps -format=p1689 --p1689-targeted-file-name=%t/User.cpp --p1689-targeted-output=%t/User.o \
+// RUN:   -- -std=c++20 -c \
+// RUN:   | FileCheck %t/User.cpp -DPREFIX=%/t
 
 //--- P1689.json.in
 [
@@ -47,6 +64,31 @@
 import :impl_part;
 export void Hello();
 
+// CHECK: {
+// CHECK-NEXT:   "revision": 0,
+// CHECK-NEXT:   "rules": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "primary-output": "[[PREFIX]]/M.o",
+// CHECK-NEXT:       "provides": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "is-interface": true,
+// CHECK-NEXT:           "logical-name": "M",
+// CHECK-NEXT:           "source-path": "[[PREFIX]]/M.cppm"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "requires": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "logical-name": "M:interface_part"
+// CHECK-NEXT:         },
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "logical-name": "M:impl_part"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ]
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ],
+// CHECK-NEXT:   "version": 1
+// CHECK-NEXT: }
+
 //--- Impl.cpp
 module;
 #include "header.mock"
@@ -55,6 +97,21 @@
     std::cout << "Hello ";
 }
 
+// CHECK: {
+// CHECK-NEXT:   "revision": 0,
+// CHECK-NEXT:   "rules": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "primary-output": "[[PREFIX]]/Impl.o",
+// CHECK-NEXT:       "requires": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "logical-name": "M"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ]
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ],
+// CHECK-NEXT:   "version": 1
+// CHECK-NEXT: }
+
 //--- impl_part.cppm
 module;
 #include "header.mock"
@@ -66,10 +123,49 @@
     std::cout << W << std::endl;
 }
 
+// CHECK: {
+// CHECK-NEXT:   "revision": 0,
+// CHECK-NEXT:   "rules": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "primary-output": "[[PREFIX]]/impl_part.o",
+// CHECK-NEXT:       "provides": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "is-interface": false,
+// CHECK-NEXT:           "logical-name": "M:impl_part",
+// CHECK-NEXT:           "source-path": "[[PREFIX]]/impl_part.cppm"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "requires": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "logical-name": "M:interface_part"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ]
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ],
+// CHECK-NEXT:   "version": 1
+// CHECK-NEXT: }
+
 //--- interface_part.cppm
 export module M:interface_part;
 export void World();
 
+// CHECK: {
+// CHECK-NEXT:   "revision": 0,
+// CHECK-NEXT:   "rules": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "primary-output": "[[PREFIX]]/interface_part.o",
+// CHECK-NEXT:       "provides": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "is-interface": true,
+// CHECK-NEXT:           "logical-name": "M:interface_part",
+// CHECK-NEXT:           "source-path": "[[PREFIX]]/interface_part.cppm"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ]
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ],
+// CHECK-NEXT:   "version": 1
+// CHECK-NEXT: }
+
 //--- User.cpp
 import M;
 import third_party_module;
@@ -79,6 +175,24 @@
     return 0;
 }
 
+// CHECK: {
+// CHECK-NEXT:   "revision": 0,
+// CHECK-NEXT:   "rules": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "primary-output": "[[PREFIX]]/User.o",
+// CHECK-NEXT:       "requires": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "logical-name": "M"
+// CHECK-NEXT:         },
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "logical-name": "third_party_module"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ]
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ],
+// CHECK-NEXT:   "version": 1
+// CHECK-NEXT: }
+
 //--- Checks.cpp
 // CHECK: {
 // CHECK-NEXT:   "revision": 0,
Index: clang/lib/Tooling/CompilationDatabase.cpp
===================================================================
--- clang/lib/Tooling/CompilationDatabase.cpp
+++ clang/lib/Tooling/CompilationDatabase.cpp
@@ -320,10 +320,9 @@
 }
 
 std::unique_ptr<FixedCompilationDatabase>
-FixedCompilationDatabase::loadFromCommandLine(int &Argc,
-                                              const char *const *Argv,
-                                              std::string &ErrorMsg,
-                                              const Twine &Directory) {
+FixedCompilationDatabase::loadFromCommandLine(
+    int &Argc, const char *const *Argv, std::string &ErrorMsg,
+    const Twine &Directory, StringRef FilePath, StringRef OutputPath) {
   ErrorMsg.clear();
   if (Argc == 0)
     return nullptr;
@@ -336,7 +335,8 @@
   std::vector<std::string> StrippedArgs;
   if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg))
     return nullptr;
-  return std::make_unique<FixedCompilationDatabase>(Directory, StrippedArgs);
+  return std::make_unique<FixedCompilationDatabase>(Directory, StrippedArgs,
+                                                    FilePath, OutputPath);
 }
 
 std::unique_ptr<FixedCompilationDatabase>
@@ -369,17 +369,21 @@
 }
 
 FixedCompilationDatabase::FixedCompilationDatabase(
-    const Twine &Directory, ArrayRef<std::string> CommandLine) {
+    const Twine &Directory, ArrayRef<std::string> CommandLine,
+    StringRef FilePath, StringRef OutputPath) {
   std::vector<std::string> ToolCommandLine(1, GetClangToolCommand());
   ToolCommandLine.insert(ToolCommandLine.end(),
                          CommandLine.begin(), CommandLine.end());
-  CompileCommands.emplace_back(Directory, StringRef(),
-                               std::move(ToolCommandLine),
-                               StringRef());
+  if (!FilePath.empty())
+    ToolCommandLine.push_back(std::string(FilePath));
+  CompileCommands.emplace_back(Directory, FilePath, std::move(ToolCommandLine),
+                               OutputPath);
 }
 
 std::vector<CompileCommand>
 FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const {
+  assert(CompileCommands[0].Filename.empty() &&
+         "We've already set the filename for the fixed compilation databse.");
   std::vector<CompileCommand> Result(CompileCommands);
   Result[0].CommandLine.push_back(std::string(FilePath));
   Result[0].Filename = std::string(FilePath);
Index: clang/include/clang/Tooling/CompilationDatabase.h
===================================================================
--- clang/include/clang/Tooling/CompilationDatabase.h
+++ clang/include/clang/Tooling/CompilationDatabase.h
@@ -180,9 +180,13 @@
   /// \param Argv Points to the command line arguments.
   /// \param ErrorMsg Contains error text if the function returns null pointer.
   /// \param Directory The base directory used in the FixedCompilationDatabase.
+  /// \param FilePath The file path used in the FixedCompilationDatabase.
+  /// \param OutputPath The output path used in the FixedCompilationDatabase.
   static std::unique_ptr<FixedCompilationDatabase>
   loadFromCommandLine(int &Argc, const char *const *Argv, std::string &ErrorMsg,
-                      const Twine &Directory = ".");
+                      const Twine &Directory = ".",
+                      StringRef FilePath = StringRef(),
+                      StringRef OutputPath = StringRef());
 
   /// Reads flags from the given file, one-per-line.
   /// Returns nullptr and sets ErrorMessage if we can't read the file.
@@ -195,18 +199,28 @@
   loadFromBuffer(StringRef Directory, StringRef Data, std::string &ErrorMsg);
 
   /// Constructs a compilation data base from a specified directory
-  /// and command line.
+  /// command line, file path (optional) and output path (Optional).
   FixedCompilationDatabase(const Twine &Directory,
-                           ArrayRef<std::string> CommandLine);
+                           ArrayRef<std::string> CommandLine,
+                           StringRef FilePath = StringRef(),
+                           StringRef OutputPath = StringRef());
 
   /// Returns the given compile command.
   ///
   /// Will always return a vector with one entry that contains the directory
   /// and command line specified at construction with "clang-tool" as argv[0]
   /// and 'FilePath' as positional argument.
+  ///
+  /// This requires the FixedCompilationDatabase haven't set FilePath when
+  /// construction.
   std::vector<CompileCommand>
   getCompileCommands(StringRef FilePath) const override;
 
+  /// Returns the compile commands.
+  std::vector<CompileCommand> getAllCompileCommands() const override {
+    return CompileCommands;
+  }
+
 private:
   /// This is built up to contain a single entry vector to be returned from
   /// getCompileCommands after adding the positional argument.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to