xref: /llvm-project/clang/test/ClangScanDeps/header-search-pruning-transitive.c (revision 9d4837f47c48c634d4a0ac799188e1f5332495ef)
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