diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -55,6 +55,14 @@ Optimize(CI); + // The original invocation probably didn't have strict context hash enabled. + // We will use the context hash of this invocation to distinguish between + // multiple incompatible versions of the same module and will use it when + // reporting dependencies to the clients. Let's make sure we're using + // **strict** context hash in order to prevent accidental sharing of + // incompatible modules (e.g. with differences in search paths). + CI.getHeaderSearchOpts().ModulesStrictContextHash = true; + return CI; } diff --git a/clang/test/ClangScanDeps/Inputs/modules-context-hash/a/dep.h b/clang/test/ClangScanDeps/Inputs/modules-context-hash/a/dep.h new file mode 100644 diff --git a/clang/test/ClangScanDeps/Inputs/modules-context-hash/b/dep.h b/clang/test/ClangScanDeps/Inputs/modules-context-hash/b/dep.h new file mode 100644 diff --git a/clang/test/ClangScanDeps/Inputs/modules-context-hash/cdb.json.template b/clang/test/ClangScanDeps/Inputs/modules-context-hash/cdb.json.template new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/modules-context-hash/cdb.json.template @@ -0,0 +1,12 @@ +[ + { + "directory": "DIR", + "command": "clang -c DIR/tu.c -fmodules -fmodules-cache-path=DIR/cache -IDIR/a -o DIR/tu_a.o", + "file": "DIR/tu.c" + }, + { + "directory": "DIR", + "command": "clang -c DIR/tu.c -fmodules -fmodules-cache-path=DIR/cache -IDIR/b -o DIR/tu_b.o", + "file": "DIR/tu.c" + } +] diff --git a/clang/test/ClangScanDeps/Inputs/modules-context-hash/mod.h b/clang/test/ClangScanDeps/Inputs/modules-context-hash/mod.h new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/modules-context-hash/mod.h @@ -0,0 +1 @@ +#include "dep.h" diff --git a/clang/test/ClangScanDeps/Inputs/modules-context-hash/module.modulemap b/clang/test/ClangScanDeps/Inputs/modules-context-hash/module.modulemap new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/modules-context-hash/module.modulemap @@ -0,0 +1 @@ +module mod { header "mod.h" } diff --git a/clang/test/ClangScanDeps/Inputs/modules-context-hash/tu.c b/clang/test/ClangScanDeps/Inputs/modules-context-hash/tu.c new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/Inputs/modules-context-hash/tu.c @@ -0,0 +1 @@ +#include "mod.h" diff --git a/clang/test/ClangScanDeps/modules-context-hash.c b/clang/test/ClangScanDeps/modules-context-hash.c new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/modules-context-hash.c @@ -0,0 +1,89 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: cp -r %S/Inputs/modules-context-hash/* %t + +// Check that the scanner reports the same module as distinct dependencies when +// a single translation unit gets compiled with multiple command-lines that +// produce different **strict** context hashes. + +// RUN: sed "s|DIR|%/t|g" %S/Inputs/modules-context-hash/cdb.json.template > %t/cdb.json +// RUN: echo -%t > %t/result.json +// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -j 1 >> %t/result.json +// RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck %s -check-prefix=CHECK + +// CHECK: -[[PREFIX:.*]] +// CHECK-NEXT: { +// CHECK-NEXT: "modules": [ +// CHECK-NEXT: { +// CHECK-NEXT: "clang-module-deps": [], +// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", +// CHECK-NEXT: "command-line": [ +// CHECK-NEXT: "-cc1" +// CHECK: "-emit-module" +// CHECK: "-I" +// CHECK: "[[PREFIX]]/a" +// CHECK: "-fmodule-name=mod" +// CHECK: ], +// CHECK-NEXT: "context-hash": "[[HASH_MOD_A:.*]]", +// CHECK-NEXT: "file-deps": [ +// CHECK-NEXT: "[[PREFIX]]/a/dep.h", +// CHECK-NEXT: "[[PREFIX]]/mod.h", +// CHECK-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK-NEXT: ], +// CHECK-NEXT: "name": "mod" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "clang-module-deps": [], +// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", +// CHECK-NEXT: "command-line": [ +// CHECK-NEXT: "-cc1" +// CHECK: "-emit-module" +// CHECK: "-I" +// CHECK: "[[PREFIX]]/b" +// CHECK: "-fmodule-name=mod" +// CHECK: ], +// CHECK-NEXT: "context-hash": "[[HASH_MOD_B:.*]]", +// CHECK-NEXT: "file-deps": [ +// CHECK-NEXT: "[[PREFIX]]/b/dep.h", +// CHECK-NEXT: "[[PREFIX]]/mod.h", +// CHECK-NEXT: "[[PREFIX]]/module.modulemap" +// CHECK-NEXT: ], +// CHECK-NEXT: "name": "mod" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "translation-units": [ +// CHECK-NEXT: { +// CHECK-NEXT: "clang-context-hash": "{{.*}}", +// CHECK-NEXT: "clang-module-deps": [ +// CHECK-NEXT: { +// CHECK-NEXT: "context-hash": "[[HASH_MOD_A]]", +// CHECK-NEXT: "module-name": "mod" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "command-line": [ +// CHECK-NEXT: "-fno-implicit-modules", +// CHECK-NEXT: "-fno-implicit-module-maps" +// CHECK-NEXT: ], +// CHECK-NEXT: "file-deps": [ +// CHECK-NEXT: "[[PREFIX]]/tu.c" +// CHECK-NEXT: ], +// CHECK-NEXT: "input-file": "[[PREFIX]]/tu.c" +// CHECK-NEXT: }, +// CHECK-NEXT: { +// CHECK-NEXT: "clang-context-hash": "{{.*}}", +// CHECK-NEXT: "clang-module-deps": [ +// CHECK-NEXT: { +// CHECK-NEXT: "context-hash": "[[HASH_MOD_B]]", +// CHECK-NEXT: "module-name": "mod" +// CHECK-NEXT: } +// CHECK-NEXT: ], +// CHECK-NEXT: "command-line": [ +// CHECK-NEXT: "-fno-implicit-modules", +// CHECK-NEXT: "-fno-implicit-module-maps" +// CHECK-NEXT: ], +// CHECK-NEXT: "file-deps": [ +// CHECK-NEXT: "[[PREFIX]]/tu.c" +// CHECK-NEXT: ], +// CHECK-NEXT: "input-file": "[[PREFIX]]/tu.c" +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: }