Changeset View
Changeset View
Standalone View
Standalone View
clang/unittests/Tooling/DependencyScannerTest.cpp
- This file was added.
1 | //===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===// | ||||
---|---|---|---|---|---|
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 | //===----------------------------------------------------------------------===// | ||||
8 | | ||||
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/Tooling.h" | ||||
18 | #include "llvm/ADT/STLExtras.h" | ||||
19 | #include "llvm/Support/Path.h" | ||||
20 | #include "llvm/Support/TargetRegistry.h" | ||||
21 | #include "llvm/Support/TargetSelect.h" | ||||
22 | #include "gtest/gtest.h" | ||||
23 | #include <algorithm> | ||||
24 | #include <string> | ||||
25 | | ||||
26 | namespace clang { | ||||
27 | namespace tooling { | ||||
28 | | ||||
29 | namespace { | ||||
30 | | ||||
31 | /// Prints out all of the gathered dependencies into a string. | ||||
32 | class TestFileCollector : public DependencyFileGenerator { | ||||
33 | public: | ||||
34 | TestFileCollector(DependencyOutputOptions &Opts, | ||||
35 | std::vector<std::string> &Deps) | ||||
36 | : DependencyFileGenerator(Opts), Deps(Deps) {} | ||||
37 | | ||||
38 | void finishedMainFile(DiagnosticsEngine &Diags) override { | ||||
39 | Deps = getDependencies(); | ||||
40 | } | ||||
41 | | ||||
42 | private: | ||||
43 | std::vector<std::string> &Deps; | ||||
44 | }; | ||||
45 | | ||||
46 | class TestDependencyScanningAction : public tooling::ToolAction { | ||||
47 | public: | ||||
48 | TestDependencyScanningAction(std::vector<std::string> &Deps) : Deps(Deps) {} | ||||
49 | | ||||
50 | bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, | ||||
51 | FileManager *FileMgr, | ||||
52 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, | ||||
53 | DiagnosticConsumer *DiagConsumer) override { | ||||
54 | CompilerInstance Compiler(std::move(PCHContainerOps)); | ||||
55 | Compiler.setInvocation(std::move(Invocation)); | ||||
56 | Compiler.setFileManager(FileMgr); | ||||
57 | | ||||
58 | Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); | ||||
59 | if (!Compiler.hasDiagnostics()) | ||||
60 | return false; | ||||
61 | | ||||
62 | Compiler.createSourceManager(*FileMgr); | ||||
63 | Compiler.addDependencyCollector(std::make_shared<TestFileCollector>( | ||||
64 | Compiler.getInvocation().getDependencyOutputOpts(), Deps)); | ||||
65 | | ||||
66 | auto Action = llvm::make_unique<PreprocessOnlyAction>(); | ||||
67 | return Compiler.ExecuteAction(*Action); | ||||
68 | } | ||||
69 | | ||||
70 | private: | ||||
71 | std::vector<std::string> &Deps; | ||||
72 | }; | ||||
73 | | ||||
74 | } // namespace | ||||
75 | | ||||
76 | TEST(DependencyScanner, ScanDepsReuseFilemanager) { | ||||
77 | std::vector<std::string> Compilation = {"-c", "-E", "-MT", "test.cpp.o"}; | ||||
78 | StringRef CWD = "/root"; | ||||
79 | FixedCompilationDatabase CDB(CWD, Compilation); | ||||
80 | | ||||
81 | auto VFS = new llvm::vfs::InMemoryFileSystem(); | ||||
82 | VFS->setCurrentWorkingDirectory(CWD); | ||||
83 | VFS->addFile("/root/header.h", 0, llvm::MemoryBuffer::getMemBuffer("\n")); | ||||
84 | VFS->addHardLink("/root/symlink.h", "/root/header.h"); | ||||
85 | VFS->addFile("/root/test.cpp", 0, | ||||
86 | llvm::MemoryBuffer::getMemBuffer( | ||||
87 | "#include \"symlink.h\"\n#include \"header.h\"\n")); | ||||
88 | | ||||
89 | ClangTool Tool(CDB, {"test.cpp"}, std::make_shared<PCHContainerOperations>(), | ||||
90 | VFS); | ||||
91 | Tool.clearArgumentsAdjusters(); | ||||
92 | std::vector<std::string> Deps; | ||||
93 | TestDependencyScanningAction Action(Deps); | ||||
94 | Tool.run(&Action); | ||||
95 | // The first invocation should return dependencies in order of access. | ||||
96 | ASSERT_EQ(Deps.size(), 3u); | ||||
97 | EXPECT_EQ(Deps[0], "/root/test.cpp"); | ||||
98 | EXPECT_EQ(Deps[1], "/root/symlink.h"); | ||||
99 | EXPECT_EQ(Deps[2], "/root/header.h"); | ||||
100 | | ||||
101 | // The file manager should still have two FileEntries, as one file is a | ||||
102 | // hardlink. | ||||
103 | FileManager &Files = Tool.getFiles(); | ||||
104 | EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u); | ||||
105 | | ||||
106 | Deps.clear(); | ||||
107 | Tool.run(&Action); | ||||
108 | // The second invocation should have the same order of dependencies. | ||||
109 | ASSERT_EQ(Deps.size(), 3u); | ||||
110 | EXPECT_EQ(Deps[0], "/root/test.cpp"); | ||||
111 | EXPECT_EQ(Deps[1], "/root/symlink.h"); | ||||
112 | EXPECT_EQ(Deps[2], "/root/header.h"); | ||||
113 | | ||||
114 | EXPECT_EQ(Files.getNumUniqueRealFiles(), 2u); | ||||
115 | } | ||||
116 | | ||||
117 | } // end namespace tooling | ||||
118 | } // end namespace clang |