[SCFToGPU] Convert scf.parallel+scf.reduce to gpu.all_reduce (#122782)
[llvm-project.git] / clang / unittests / Tooling / DependencyScanning / DependencyScannerTest.cpp
blobe1c4770805992065a970449d8a2907617a872fc6
1 //===- DependencyScannerTest.cpp ------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "clang/AST/ASTConsumer.h"
10 #include "clang/AST/DeclCXX.h"
11 #include "clang/AST/DeclGroup.h"
12 #include "clang/Frontend/ASTUnit.h"
13 #include "clang/Frontend/CompilerInstance.h"
14 #include "clang/Frontend/FrontendAction.h"
15 #include "clang/Frontend/FrontendActions.h"
16 #include "clang/Tooling/CompilationDatabase.h"
17 #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
18 #include "clang/Tooling/Tooling.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/MC/TargetRegistry.h"
21 #include "llvm/Support/FormatVariadic.h"
22 #include "llvm/Support/Path.h"
23 #include "llvm/Support/TargetSelect.h"
24 #include "llvm/Testing/Support/Error.h"
25 #include "gtest/gtest.h"
26 #include <algorithm>
27 #include <string>
29 using namespace clang;
30 using namespace tooling;
31 using namespace dependencies;
33 namespace {
35 /// Prints out all of the gathered dependencies into a string.
36 class TestFileCollector : public DependencyFileGenerator {
37 public:
38 TestFileCollector(DependencyOutputOptions &Opts,
39 std::vector<std::string> &Deps)
40 : DependencyFileGenerator(Opts), Deps(Deps) {}
42 void finishedMainFile(DiagnosticsEngine &Diags) override {
43 auto NewDeps = getDependencies();
44 Deps.insert(Deps.end(), NewDeps.begin(), NewDeps.end());
47 private:
48 std::vector<std::string> &Deps;
51 class TestDependencyScanningAction : public tooling::ToolAction {
52 public:
53 TestDependencyScanningAction(std::vector<std::string> &Deps) : Deps(Deps) {}
55 bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation,
56 FileManager *FileMgr,
57 std::shared_ptr<PCHContainerOperations> PCHContainerOps,
58 DiagnosticConsumer *DiagConsumer) override {
59 CompilerInstance Compiler(std::move(PCHContainerOps));
60 Compiler.setInvocation(std::move(Invocation));
61 Compiler.setFileManager(FileMgr);
63 Compiler.createDiagnostics(FileMgr->getVirtualFileSystem(), DiagConsumer,
64 /*ShouldOwnClient=*/false);
65 if (!Compiler.hasDiagnostics())
66 return false;
68 Compiler.createSourceManager(*FileMgr);
69 Compiler.addDependencyCollector(std::make_shared<TestFileCollector>(
70 Compiler.getInvocation().getDependencyOutputOpts(), Deps));
72 auto Action = std::make_unique<PreprocessOnlyAction>();
73 return Compiler.ExecuteAction(*Action);
76 private:
77 std::vector<std::string> &Deps;
80 } // namespace
82 TEST(DependencyScanner, ScanDepsReuseFilemanager) {
83 std::vector<std::string> Compilation = {"-c", "-E", "-MT", "test.cpp.o"};
84 StringRef CWD = "/root";
85 FixedCompilationDatabase CDB(CWD, Compilation);
87 auto VFS = new llvm::vfs::InMemoryFileSystem();
88 VFS->setCurrentWorkingDirectory(CWD);
89 auto Sept = llvm::sys::path::get_separator();
90 std::string HeaderPath =
91 std::string(llvm::formatv("{0}root{0}header.h", Sept));
92 std::string SymlinkPath =
93 std::string(llvm::formatv("{0}root{0}symlink.h", Sept));
94 std::string TestPath = std::string(llvm::formatv("{0}root{0}test.cpp", Sept));
96 VFS->addFile(HeaderPath, 0, llvm::MemoryBuffer::getMemBuffer("\n"));
97 VFS->addHardLink(SymlinkPath, HeaderPath);
98 VFS->addFile(TestPath, 0,
99 llvm::MemoryBuffer::getMemBuffer(
100 "#include \"symlink.h\"\n#include \"header.h\"\n"));
102 ClangTool Tool(CDB, {"test.cpp"}, std::make_shared<PCHContainerOperations>(),
103 VFS);
104 Tool.clearArgumentsAdjusters();
105 std::vector<std::string> Deps;
106 TestDependencyScanningAction Action(Deps);
107 Tool.run(&Action);
108 using llvm::sys::path::convert_to_slash;
109 // The first invocation should return dependencies in order of access.
110 ASSERT_EQ(Deps.size(), 3u);
111 EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp");
112 EXPECT_EQ(convert_to_slash(Deps[1]), "/root/symlink.h");
113 EXPECT_EQ(convert_to_slash(Deps[2]), "/root/header.h");
115 // The file manager should still have two FileEntries, as one file is a
116 // hardlink.
117 FileManager &Files = Tool.getFiles();
118 EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u);
120 Deps.clear();
121 Tool.run(&Action);
122 // The second invocation should have the same order of dependencies.
123 ASSERT_EQ(Deps.size(), 3u);
124 EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp");
125 EXPECT_EQ(convert_to_slash(Deps[1]), "/root/symlink.h");
126 EXPECT_EQ(convert_to_slash(Deps[2]), "/root/header.h");
128 EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u);
131 TEST(DependencyScanner, ScanDepsReuseFilemanagerSkippedFile) {
132 std::vector<std::string> Compilation = {"-c", "-E", "-MT", "test.cpp.o"};
133 StringRef CWD = "/root";
134 FixedCompilationDatabase CDB(CWD, Compilation);
136 auto VFS = new llvm::vfs::InMemoryFileSystem();
137 VFS->setCurrentWorkingDirectory(CWD);
138 auto Sept = llvm::sys::path::get_separator();
139 std::string HeaderPath =
140 std::string(llvm::formatv("{0}root{0}header.h", Sept));
141 std::string SymlinkPath =
142 std::string(llvm::formatv("{0}root{0}symlink.h", Sept));
143 std::string TestPath = std::string(llvm::formatv("{0}root{0}test.cpp", Sept));
144 std::string Test2Path =
145 std::string(llvm::formatv("{0}root{0}test2.cpp", Sept));
147 VFS->addFile(HeaderPath, 0,
148 llvm::MemoryBuffer::getMemBuffer("#pragma once\n"));
149 VFS->addHardLink(SymlinkPath, HeaderPath);
150 VFS->addFile(TestPath, 0,
151 llvm::MemoryBuffer::getMemBuffer(
152 "#include \"header.h\"\n#include \"symlink.h\"\n"));
153 VFS->addFile(Test2Path, 0,
154 llvm::MemoryBuffer::getMemBuffer(
155 "#include \"symlink.h\"\n#include \"header.h\"\n"));
157 ClangTool Tool(CDB, {"test.cpp", "test2.cpp"},
158 std::make_shared<PCHContainerOperations>(), VFS);
159 Tool.clearArgumentsAdjusters();
160 std::vector<std::string> Deps;
161 TestDependencyScanningAction Action(Deps);
162 Tool.run(&Action);
163 using llvm::sys::path::convert_to_slash;
164 ASSERT_EQ(Deps.size(), 6u);
165 EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp");
166 EXPECT_EQ(convert_to_slash(Deps[1]), "/root/header.h");
167 EXPECT_EQ(convert_to_slash(Deps[2]), "/root/symlink.h");
168 EXPECT_EQ(convert_to_slash(Deps[3]), "/root/test2.cpp");
169 EXPECT_EQ(convert_to_slash(Deps[4]), "/root/symlink.h");
170 EXPECT_EQ(convert_to_slash(Deps[5]), "/root/header.h");
173 TEST(DependencyScanner, ScanDepsReuseFilemanagerHasInclude) {
174 std::vector<std::string> Compilation = {"-c", "-E", "-MT", "test.cpp.o"};
175 StringRef CWD = "/root";
176 FixedCompilationDatabase CDB(CWD, Compilation);
178 auto VFS = new llvm::vfs::InMemoryFileSystem();
179 VFS->setCurrentWorkingDirectory(CWD);
180 auto Sept = llvm::sys::path::get_separator();
181 std::string HeaderPath =
182 std::string(llvm::formatv("{0}root{0}header.h", Sept));
183 std::string SymlinkPath =
184 std::string(llvm::formatv("{0}root{0}symlink.h", Sept));
185 std::string TestPath = std::string(llvm::formatv("{0}root{0}test.cpp", Sept));
187 VFS->addFile(HeaderPath, 0, llvm::MemoryBuffer::getMemBuffer("\n"));
188 VFS->addHardLink(SymlinkPath, HeaderPath);
189 VFS->addFile(
190 TestPath, 0,
191 llvm::MemoryBuffer::getMemBuffer("#if __has_include(\"header.h\") && "
192 "__has_include(\"symlink.h\")\n#endif"));
194 ClangTool Tool(CDB, {"test.cpp", "test.cpp"},
195 std::make_shared<PCHContainerOperations>(), VFS);
196 Tool.clearArgumentsAdjusters();
197 std::vector<std::string> Deps;
198 TestDependencyScanningAction Action(Deps);
199 Tool.run(&Action);
200 using llvm::sys::path::convert_to_slash;
201 ASSERT_EQ(Deps.size(), 6u);
202 EXPECT_EQ(convert_to_slash(Deps[0]), "/root/test.cpp");
203 EXPECT_EQ(convert_to_slash(Deps[1]), "/root/header.h");
204 EXPECT_EQ(convert_to_slash(Deps[2]), "/root/symlink.h");
205 EXPECT_EQ(convert_to_slash(Deps[3]), "/root/test.cpp");
206 EXPECT_EQ(convert_to_slash(Deps[4]), "/root/header.h");
207 EXPECT_EQ(convert_to_slash(Deps[5]), "/root/symlink.h");
210 TEST(DependencyScanner, ScanDepsWithFS) {
211 std::vector<std::string> CommandLine = {"clang",
212 "-target",
213 "x86_64-apple-macosx10.7",
214 "-c",
215 "test.cpp",
216 "-o"
217 "test.cpp.o"};
218 StringRef CWD = "/root";
220 auto VFS = new llvm::vfs::InMemoryFileSystem();
221 VFS->setCurrentWorkingDirectory(CWD);
222 auto Sept = llvm::sys::path::get_separator();
223 std::string HeaderPath =
224 std::string(llvm::formatv("{0}root{0}header.h", Sept));
225 std::string TestPath = std::string(llvm::formatv("{0}root{0}test.cpp", Sept));
227 VFS->addFile(HeaderPath, 0, llvm::MemoryBuffer::getMemBuffer("\n"));
228 VFS->addFile(TestPath, 0,
229 llvm::MemoryBuffer::getMemBuffer("#include \"header.h\"\n"));
231 DependencyScanningService Service(ScanningMode::DependencyDirectivesScan,
232 ScanningOutputFormat::Make);
233 DependencyScanningTool ScanTool(Service, VFS);
235 std::string DepFile;
236 ASSERT_THAT_ERROR(
237 ScanTool.getDependencyFile(CommandLine, CWD).moveInto(DepFile),
238 llvm::Succeeded());
239 using llvm::sys::path::convert_to_slash;
240 EXPECT_EQ(convert_to_slash(DepFile),
241 "test.cpp.o: /root/test.cpp /root/header.h\n");
244 TEST(DependencyScanner, ScanDepsWithModuleLookup) {
245 std::vector<std::string> CommandLine = {
246 "clang",
247 "-target",
248 "x86_64-apple-macosx10.7",
249 "-c",
250 "test.m",
251 "-o"
252 "test.m.o",
253 "-fmodules",
254 "-I/root/SomeSources",
256 StringRef CWD = "/root";
258 auto VFS = new llvm::vfs::InMemoryFileSystem();
259 VFS->setCurrentWorkingDirectory(CWD);
260 auto Sept = llvm::sys::path::get_separator();
261 std::string OtherPath =
262 std::string(llvm::formatv("{0}root{0}SomeSources{0}other.h", Sept));
263 std::string TestPath = std::string(llvm::formatv("{0}root{0}test.m", Sept));
265 VFS->addFile(OtherPath, 0, llvm::MemoryBuffer::getMemBuffer("\n"));
266 VFS->addFile(TestPath, 0, llvm::MemoryBuffer::getMemBuffer("@import Foo;\n"));
268 struct InterceptorFS : llvm::vfs::ProxyFileSystem {
269 std::vector<std::string> StatPaths;
270 std::vector<std::string> ReadFiles;
272 InterceptorFS(IntrusiveRefCntPtr<FileSystem> UnderlyingFS)
273 : ProxyFileSystem(UnderlyingFS) {}
275 llvm::ErrorOr<llvm::vfs::Status> status(const Twine &Path) override {
276 StatPaths.push_back(Path.str());
277 return ProxyFileSystem::status(Path);
280 llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
281 openFileForRead(const Twine &Path) override {
282 ReadFiles.push_back(Path.str());
283 return ProxyFileSystem::openFileForRead(Path);
287 auto InterceptFS = llvm::makeIntrusiveRefCnt<InterceptorFS>(VFS);
289 DependencyScanningService Service(ScanningMode::DependencyDirectivesScan,
290 ScanningOutputFormat::Make);
291 DependencyScanningTool ScanTool(Service, InterceptFS);
293 // This will fail with "fatal error: module 'Foo' not found" but it doesn't
294 // matter, the point of the test is to check that files are not read
295 // unnecessarily.
296 std::string DepFile;
297 ASSERT_THAT_ERROR(
298 ScanTool.getDependencyFile(CommandLine, CWD).moveInto(DepFile),
299 llvm::Failed());
301 EXPECT_TRUE(llvm::find(InterceptFS->StatPaths, OtherPath) ==
302 InterceptFS->StatPaths.end());
303 EXPECT_EQ(InterceptFS->ReadFiles, std::vector<std::string>{"test.m"});