Commit d816d9bd authored by Michael Spencer's avatar Michael Spencer
Browse files

[clang][ScanDeps] Fix issue with multiple commands with the same input.

Previously, given a CompilationDatabase with two commands for the same
source file we would report that file twice with the union of the
dependencies for each command both times.

This was due to the way `ClangTool` runs actions given an input source
file (see the comment in `DependencyScanningTool.cpp`). This commit adds
a `SingleCommandCompilationDatabase` that is created with each
`CompileCommand` in the original CDB, which is then used for each
`ClangTool` invocation. This gives us a single run of
`DependencyScanningAction` per `CompileCommand`.

I looked at using `AllTUsToolExecutor` which is a parallel tool
executor, but I'm not sure it's suitable for `clang-scan-deps` as it
does a lot more sharing of state than `AllTUsToolExecutor` expects.

Differential Revision: https://reviews.llvm.org/D69643
parent 19f1dc7b
Loading
Loading
Loading
Loading
+4 −6
Original line number Diff line number Diff line
@@ -26,9 +26,7 @@ public:
  ///
  /// \param Compilations     The reference to the compilation database that's
  /// used by the clang tool.
  DependencyScanningTool(
      DependencyScanningService &Service,
      const clang::tooling::CompilationDatabase &Compilations);
  DependencyScanningTool(DependencyScanningService &Service);

  /// Print out the dependency information into a string using the dependency
  /// file format that is specified in the options (-MD is the default) and
@@ -36,13 +34,13 @@ public:
  ///
  /// \returns A \c StringError with the diagnostic output if clang errors
  /// occurred, dependency file contents otherwise.
  llvm::Expected<std::string> getDependencyFile(const std::string &Input,
  llvm::Expected<std::string>
  getDependencyFile(const tooling::CompilationDatabase &Compilations,
                    StringRef CWD);

private:
  const ScanningOutputFormat Format;
  DependencyScanningWorker Worker;
  const tooling::CompilationDatabase &Compilations;
};

} // end namespace dependencies
+14 −6
Original line number Diff line number Diff line
@@ -23,14 +23,12 @@ namespace tooling{
namespace dependencies{

DependencyScanningTool::DependencyScanningTool(
    DependencyScanningService &Service,
    const tooling::CompilationDatabase &Compilations)
    : Format(Service.getFormat()), Worker(Service), Compilations(Compilations) {
    DependencyScanningService &Service)
    : Format(Service.getFormat()), Worker(Service) {
}

llvm::Expected<std::string>
DependencyScanningTool::getDependencyFile(const std::string &Input,
                                          StringRef CWD) {
llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
    const tooling::CompilationDatabase &Compilations, StringRef CWD) {
  /// Prints out all of the gathered dependencies into a string.
  class MakeDependencyPrinterConsumer : public DependencyConsumer {
  public:
@@ -140,6 +138,16 @@ DependencyScanningTool::getDependencyFile(const std::string &Input,
    std::string ContextHash;
  };

  
  // We expect a single command here because if a source file occurs multiple
  // times in the original CDB, then `computeDependencies` would run the
  // `DependencyScanningAction` once for every time the input occured in the
  // CDB. Instead we split up the CDB into single command chunks to avoid this
  // behavior.
  assert(Compilations.getAllCompileCommands().size() == 1 &&
         "Expected a compilation database with a single command!");
  std::string Input = Compilations.getAllCompileCommands().front().Filename;
  
  if (Format == ScanningOutputFormat::Make) {
    MakeDependencyPrinterConsumer Consumer;
    auto Result =
+5 −0
Original line number Diff line number Diff line
@@ -8,5 +8,10 @@
  "directory": "DIR",
  "command": "clang -E DIR/regular_cdb_input.cpp -IInputs",
  "file": "DIR/regular_cdb_input.cpp"
},
{
  "directory": "DIR",
  "command": "clang -E DIR/regular_cdb_input.cpp -IInputs -o adena.o",
  "file": "DIR/regular_cdb_input.cpp"
}
]
+4 −0
Original line number Diff line number Diff line
@@ -18,4 +18,8 @@
// CHECK-NEXT: fatal error: 'missing.h' file not found
// CHECK-NEXT: "missing.h"
// CHECK-NEXT: ^
// CHECK-NEXT: Error while scanning dependencies
// CHECK-NEXT: fatal error: 'missing.h' file not found
// CHECK-NEXT: "missing.h"
// CHECK-NEXT: ^
// CHECK-NEXT: EOF
+6 −3
Original line number Diff line number Diff line
@@ -9,11 +9,11 @@
// RUN: sed -e "s|DIR|%/t.dir|g" %S/Inputs/regular_cdb.json > %t.cdb
//
// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -mode preprocess-minimized-sources | \
// RUN:   FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO %s
// RUN:   FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO,CHECK3 %s
// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -mode preprocess | \
// RUN:   FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO %s
// RUN:   FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO,CHECK3 %s
// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -mode preprocess-minimized-sources \
// RUN:   -skip-excluded-pp-ranges=0 | FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO %s
// RUN:   -skip-excluded-pp-ranges=0 | FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO,CHECK3 %s
//
// Make sure we didn't produce any dependency files!
// RUN: not cat %t.dir/regular_cdb.d
@@ -40,6 +40,9 @@
// CHECK1-NEXT: Inputs{{/|\\}}header.h
// CHECK1-NEXT: Inputs{{/|\\}}header2.h

// CHECK3: regular_cdb_input.o
// CHECK2: regular_cdb_input.cpp
// CHECK2-NEXT: Inputs{{/|\\}}header.h
// CHECK2NO-NOT: header2

// CHECK3: adena.o
Loading