1 // This test checks that pruning of header search paths produces consistent dependency graphs. 2 // 3 // When pruning header search paths for a module, we can't remove any paths its dependencies use. 4 // Otherwise, we could get either of the following dependency graphs depending on the search path 5 // configuration of the particular TU that first discovered the module: 6 // X:<hash1> -> Y:<hash2> 7 // X:<hash1> -> Y:<hash3> 8 // We can't have the same version of module X depend on multiple different versions of Y based on 9 // the TU configuration. 10 // 11 // Keeping all header search paths (transitive) dependencies use will ensure we get consistent 12 // dependency graphs: 13 // X:<hash1> -> Y:<hash2> 14 // X:<hash4> -> Y:<hash3> 15 16 // RUN: rm -rf %t && mkdir %t 17 // RUN: split-file %s %t 18 19 //--- a/a.h 20 //--- b/b.h 21 //--- begin/begin.h 22 //--- end/end.h 23 //--- Y.h 24 #include "begin.h" 25 #if __has_include("a.h") 26 #include "a.h" 27 #endif 28 #include "end.h" 29 30 //--- X.h 31 #include "Y.h" 32 33 //--- module.modulemap 34 module Y { header "Y.h" } 35 module X { header "X.h" } 36 37 //--- test.c 38 #include "X.h" 39 40 //--- cdb_with_a.json.template 41 [{ 42 "file": "DIR/test.c", 43 "directory": "DIR", 44 "command": "clang -fsyntax-only test.c -fmodules -fimplicit-modules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps -Ibegin -Ia -Ib -Iend" 45 }] 46 47 //--- cdb_without_a.json.template 48 [{ 49 "file": "DIR/test.c", 50 "directory": "DIR", 51 "command": "clang -fsyntax-only test.c -fmodules -fimplicit-modules -fmodules-cache-path=DIR/module-cache -fimplicit-module-maps -Ibegin -Ib -Iend" 52 }] 53 54 // RUN: sed -e "s|DIR|%/t|g" %t/cdb_with_a.json.template > %t/cdb_with_a.json 55 // RUN: sed -e "s|DIR|%/t|g" %t/cdb_without_a.json.template > %t/cdb_without_a.json 56 57 // RUN: clang-scan-deps -compilation-database %t/cdb_with_a.json -format experimental-full -optimize-args=header-search > %t/results.json 58 // RUN: clang-scan-deps -compilation-database %t/cdb_without_a.json -format experimental-full -optimize-args=header-search >> %t/results.json 59 // RUN: cat %t/results.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t 60 61 // CHECK: { 62 // CHECK-NEXT: "modules": [ 63 // CHECK-NEXT: { 64 // CHECK-NEXT: "clang-module-deps": [ 65 // CHECK-NEXT: { 66 // CHECK-NEXT: "context-hash": "[[HASH_Y_WITH_A:.*]]", 67 // CHECK-NEXT: "module-name": "Y" 68 // CHECK-NEXT: } 69 // CHECK-NEXT: ], 70 // CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", 71 // CHECK-NEXT: "command-line": [ 72 // CHECK: ], 73 // CHECK-NEXT: "context-hash": "[[HASH_X:.*]]", 74 // CHECK-NEXT: "file-deps": [ 75 // CHECK-NEXT: "[[PREFIX]]/module.modulemap", 76 // CHECK-NEXT: "[[PREFIX]]/X.h" 77 // CHECK-NEXT: ], 78 // CHECK-NEXT: "link-libraries": [], 79 // CHECK-NEXT: "name": "X" 80 // CHECK-NEXT: }, 81 // CHECK-NEXT: { 82 // CHECK-NEXT: "clang-module-deps": [], 83 // CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", 84 // CHECK-NEXT: "command-line": [ 85 // CHECK: ], 86 // CHECK-NEXT: "context-hash": "[[HASH_Y_WITH_A]]", 87 // CHECK-NEXT: "file-deps": [ 88 // CHECK-NEXT: "[[PREFIX]]/module.modulemap", 89 // CHECK-NEXT: "[[PREFIX]]/Y.h", 90 // CHECK-NEXT: "[[PREFIX]]/begin/begin.h", 91 // CHECK-NEXT: "[[PREFIX]]/a/a.h", 92 // CHECK-NEXT: "[[PREFIX]]/end/end.h" 93 // CHECK-NEXT: ], 94 // CHECK-NEXT: "link-libraries": [], 95 // CHECK-NEXT: "name": "Y" 96 // CHECK-NEXT: } 97 // CHECK-NEXT: ], 98 // CHECK-NEXT: "translation-units": [ 99 // CHECK-NEXT: { 100 // CHECK: "clang-context-hash": "{{.*}}", 101 // CHECK-NEXT: "clang-module-deps": [ 102 // CHECK-NEXT: { 103 // CHECK-NEXT: "context-hash": "[[HASH_X]]", 104 // CHECK-NEXT: "module-name": "X" 105 // CHECK-NEXT: } 106 // CHECK-NEXT: ], 107 // CHECK-NEXT: "command-line": [ 108 // CHECK: ], 109 // CHECK: "file-deps": [ 110 // CHECK-NEXT: "[[PREFIX]]/test.c" 111 // CHECK-NEXT: ], 112 // CHECK-NEXT: "input-file": "[[PREFIX]]/test.c" 113 // CHECK-NEXT: } 114 115 // CHECK: { 116 // CHECK-NEXT: "modules": [ 117 // CHECK-NEXT: { 118 // CHECK-NEXT: "clang-module-deps": [ 119 // CHECK-NEXT: { 120 // CHECK-NEXT: "context-hash": "[[HASH_Y_WITHOUT_A:.*]]", 121 // CHECK-NEXT: "module-name": "Y" 122 // CHECK-NEXT: } 123 // CHECK-NEXT: ], 124 // CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", 125 // CHECK-NEXT: "command-line": [ 126 // CHECK: ], 127 // Here is the actual check that this module X (which imports different version of Y) 128 // also has a different context hash from the first version of module X. 129 // CHECK-NOT: "context-hash": "[[HASH_X]]", 130 // CHECK: "file-deps": [ 131 // CHECK-NEXT: "[[PREFIX]]/module.modulemap", 132 // CHECK-NEXT: "[[PREFIX]]/X.h" 133 // CHECK-NEXT: ], 134 // CHECK-NEXT: "link-libraries": [], 135 // CHECK-NEXT: "name": "X" 136 // CHECK-NEXT: }, 137 // CHECK-NEXT: { 138 // CHECK-NEXT: "clang-module-deps": [], 139 // CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap", 140 // CHECK-NEXT: "command-line": [ 141 // CHECK: ], 142 // CHECK-NEXT: "context-hash": "[[HASH_Y_WITHOUT_A]]", 143 // CHECK-NEXT: "file-deps": [ 144 // CHECK-NEXT: "[[PREFIX]]/module.modulemap", 145 // CHECK-NEXT: "[[PREFIX]]/Y.h", 146 // CHECK-NEXT: "[[PREFIX]]/begin/begin.h", 147 // CHECK-NEXT: "[[PREFIX]]/end/end.h" 148 // CHECK-NEXT: ], 149 // CHECK-NEXT: "link-libraries": [], 150 // CHECK-NEXT: "name": "Y" 151 // CHECK-NEXT: } 152 // CHECK-NEXT: ], 153 // CHECK-NEXT: "translation-units": [ 154 // CHECK-NEXT: { 155 // CHECK: "clang-context-hash": "{{.*}}", 156 // CHECK-NEXT: "clang-module-deps": [ 157 // CHECK-NEXT: { 158 // CHECK-NEXT: "context-hash": "{{.*}}", 159 // CHECK-NEXT: "module-name": "X" 160 // CHECK-NEXT: } 161 // CHECK-NEXT: ], 162 // CHECK-NEXT: "command-line": [ 163 // CHECK: ], 164 // CHECK: "file-deps": [ 165 // CHECK-NEXT: "[[PREFIX]]/test.c" 166 // CHECK-NEXT: ], 167 // CHECK-NEXT: "input-file": "[[PREFIX]]/test.c" 168 // CHECK-NEXT: } 169