annotate clang/unittests/CrossTU/CrossTranslationUnitTest.cpp @ 150:1d019706d866

LLVM10
author anatofuz
date Thu, 13 Feb 2020 15:10:13 +0900
parents
children 2e18cbf3894f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===- unittest/Tooling/CrossTranslationUnitTest.cpp - Tooling unit tests -===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8
anatofuz
parents:
diff changeset
9 #include "clang/CrossTU/CrossTranslationUnit.h"
anatofuz
parents:
diff changeset
10 #include "clang/Frontend/CompilerInstance.h"
anatofuz
parents:
diff changeset
11 #include "clang/AST/ASTConsumer.h"
anatofuz
parents:
diff changeset
12 #include "clang/Frontend/FrontendAction.h"
anatofuz
parents:
diff changeset
13 #include "clang/Tooling/Tooling.h"
anatofuz
parents:
diff changeset
14 #include "llvm/Support/FileSystem.h"
anatofuz
parents:
diff changeset
15 #include "llvm/Support/Path.h"
anatofuz
parents:
diff changeset
16 #include "llvm/Support/ToolOutputFile.h"
anatofuz
parents:
diff changeset
17 #include "gtest/gtest.h"
anatofuz
parents:
diff changeset
18 #include <cassert>
anatofuz
parents:
diff changeset
19
anatofuz
parents:
diff changeset
20 namespace clang {
anatofuz
parents:
diff changeset
21 namespace cross_tu {
anatofuz
parents:
diff changeset
22
anatofuz
parents:
diff changeset
23 namespace {
anatofuz
parents:
diff changeset
24
anatofuz
parents:
diff changeset
25 class CTUASTConsumer : public clang::ASTConsumer {
anatofuz
parents:
diff changeset
26 public:
anatofuz
parents:
diff changeset
27 explicit CTUASTConsumer(clang::CompilerInstance &CI, bool *Success)
anatofuz
parents:
diff changeset
28 : CTU(CI), Success(Success) {}
anatofuz
parents:
diff changeset
29
anatofuz
parents:
diff changeset
30 void HandleTranslationUnit(ASTContext &Ctx) {
anatofuz
parents:
diff changeset
31 auto FindFInTU = [](const TranslationUnitDecl *TU) {
anatofuz
parents:
diff changeset
32 const FunctionDecl *FD = nullptr;
anatofuz
parents:
diff changeset
33 for (const Decl *D : TU->decls()) {
anatofuz
parents:
diff changeset
34 FD = dyn_cast<FunctionDecl>(D);
anatofuz
parents:
diff changeset
35 if (FD && FD->getName() == "f")
anatofuz
parents:
diff changeset
36 break;
anatofuz
parents:
diff changeset
37 }
anatofuz
parents:
diff changeset
38 return FD;
anatofuz
parents:
diff changeset
39 };
anatofuz
parents:
diff changeset
40
anatofuz
parents:
diff changeset
41 const TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
anatofuz
parents:
diff changeset
42 const FunctionDecl *FD = FindFInTU(TU);
anatofuz
parents:
diff changeset
43 assert(FD && FD->getName() == "f");
anatofuz
parents:
diff changeset
44 bool OrigFDHasBody = FD->hasBody();
anatofuz
parents:
diff changeset
45
anatofuz
parents:
diff changeset
46 // Prepare the index file and the AST file.
anatofuz
parents:
diff changeset
47 int ASTFD;
anatofuz
parents:
diff changeset
48 llvm::SmallString<256> ASTFileName;
anatofuz
parents:
diff changeset
49 ASSERT_FALSE(
anatofuz
parents:
diff changeset
50 llvm::sys::fs::createTemporaryFile("f_ast", "ast", ASTFD, ASTFileName));
anatofuz
parents:
diff changeset
51 llvm::ToolOutputFile ASTFile(ASTFileName, ASTFD);
anatofuz
parents:
diff changeset
52
anatofuz
parents:
diff changeset
53 int IndexFD;
anatofuz
parents:
diff changeset
54 llvm::SmallString<256> IndexFileName;
anatofuz
parents:
diff changeset
55 ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD,
anatofuz
parents:
diff changeset
56 IndexFileName));
anatofuz
parents:
diff changeset
57 llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD);
anatofuz
parents:
diff changeset
58 IndexFile.os() << "c:@F@f#I# " << ASTFileName << "\n";
anatofuz
parents:
diff changeset
59 IndexFile.os().flush();
anatofuz
parents:
diff changeset
60 EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName));
anatofuz
parents:
diff changeset
61
anatofuz
parents:
diff changeset
62 StringRef SourceText = "int f(int) { return 0; }\n";
anatofuz
parents:
diff changeset
63 // This file must exist since the saved ASTFile will reference it.
anatofuz
parents:
diff changeset
64 int SourceFD;
anatofuz
parents:
diff changeset
65 llvm::SmallString<256> SourceFileName;
anatofuz
parents:
diff changeset
66 ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("input", "cpp", SourceFD,
anatofuz
parents:
diff changeset
67 SourceFileName));
anatofuz
parents:
diff changeset
68 llvm::ToolOutputFile SourceFile(SourceFileName, SourceFD);
anatofuz
parents:
diff changeset
69 SourceFile.os() << SourceText;
anatofuz
parents:
diff changeset
70 SourceFile.os().flush();
anatofuz
parents:
diff changeset
71 EXPECT_TRUE(llvm::sys::fs::exists(SourceFileName));
anatofuz
parents:
diff changeset
72
anatofuz
parents:
diff changeset
73 std::unique_ptr<ASTUnit> ASTWithDefinition =
anatofuz
parents:
diff changeset
74 tooling::buildASTFromCode(SourceText, SourceFileName);
anatofuz
parents:
diff changeset
75 ASTWithDefinition->Save(ASTFileName.str());
anatofuz
parents:
diff changeset
76 EXPECT_TRUE(llvm::sys::fs::exists(ASTFileName));
anatofuz
parents:
diff changeset
77
anatofuz
parents:
diff changeset
78 // Load the definition from the AST file.
anatofuz
parents:
diff changeset
79 llvm::Expected<const FunctionDecl *> NewFDorError = handleExpected(
anatofuz
parents:
diff changeset
80 CTU.getCrossTUDefinition(FD, "", IndexFileName, false),
anatofuz
parents:
diff changeset
81 []() { return nullptr; }, [](IndexError &) {});
anatofuz
parents:
diff changeset
82
anatofuz
parents:
diff changeset
83 if (NewFDorError) {
anatofuz
parents:
diff changeset
84 const FunctionDecl *NewFD = *NewFDorError;
anatofuz
parents:
diff changeset
85 *Success = NewFD && NewFD->hasBody() && !OrigFDHasBody;
anatofuz
parents:
diff changeset
86
anatofuz
parents:
diff changeset
87 if (NewFD) {
anatofuz
parents:
diff changeset
88 // Check GetImportedFromSourceLocation.
anatofuz
parents:
diff changeset
89 llvm::Optional<std::pair<SourceLocation, ASTUnit *>> SLocResult =
anatofuz
parents:
diff changeset
90 CTU.getImportedFromSourceLocation(NewFD->getLocation());
anatofuz
parents:
diff changeset
91 EXPECT_TRUE(SLocResult);
anatofuz
parents:
diff changeset
92 if (SLocResult) {
anatofuz
parents:
diff changeset
93 SourceLocation OrigSLoc = (*SLocResult).first;
anatofuz
parents:
diff changeset
94 ASTUnit *OrigUnit = (*SLocResult).second;
anatofuz
parents:
diff changeset
95 // OrigUnit is created internally by CTU (is not the
anatofuz
parents:
diff changeset
96 // ASTWithDefinition).
anatofuz
parents:
diff changeset
97 TranslationUnitDecl *OrigTU =
anatofuz
parents:
diff changeset
98 OrigUnit->getASTContext().getTranslationUnitDecl();
anatofuz
parents:
diff changeset
99 const FunctionDecl *FDWithDefinition = FindFInTU(OrigTU);
anatofuz
parents:
diff changeset
100 EXPECT_TRUE(FDWithDefinition);
anatofuz
parents:
diff changeset
101 if (FDWithDefinition) {
anatofuz
parents:
diff changeset
102 EXPECT_EQ(FDWithDefinition->getName(), "f");
anatofuz
parents:
diff changeset
103 EXPECT_TRUE(FDWithDefinition->isThisDeclarationADefinition());
anatofuz
parents:
diff changeset
104 EXPECT_EQ(OrigSLoc, FDWithDefinition->getLocation());
anatofuz
parents:
diff changeset
105 }
anatofuz
parents:
diff changeset
106 }
anatofuz
parents:
diff changeset
107 }
anatofuz
parents:
diff changeset
108 }
anatofuz
parents:
diff changeset
109 }
anatofuz
parents:
diff changeset
110
anatofuz
parents:
diff changeset
111 private:
anatofuz
parents:
diff changeset
112 CrossTranslationUnitContext CTU;
anatofuz
parents:
diff changeset
113 bool *Success;
anatofuz
parents:
diff changeset
114 };
anatofuz
parents:
diff changeset
115
anatofuz
parents:
diff changeset
116 class CTUAction : public clang::ASTFrontendAction {
anatofuz
parents:
diff changeset
117 public:
anatofuz
parents:
diff changeset
118 CTUAction(bool *Success, unsigned OverrideLimit)
anatofuz
parents:
diff changeset
119 : Success(Success), OverrideLimit(OverrideLimit) {}
anatofuz
parents:
diff changeset
120
anatofuz
parents:
diff changeset
121 protected:
anatofuz
parents:
diff changeset
122 std::unique_ptr<clang::ASTConsumer>
anatofuz
parents:
diff changeset
123 CreateASTConsumer(clang::CompilerInstance &CI, StringRef) override {
anatofuz
parents:
diff changeset
124 CI.getAnalyzerOpts()->CTUImportThreshold = OverrideLimit;
anatofuz
parents:
diff changeset
125 return std::make_unique<CTUASTConsumer>(CI, Success);
anatofuz
parents:
diff changeset
126 }
anatofuz
parents:
diff changeset
127
anatofuz
parents:
diff changeset
128 private:
anatofuz
parents:
diff changeset
129 bool *Success;
anatofuz
parents:
diff changeset
130 const unsigned OverrideLimit;
anatofuz
parents:
diff changeset
131 };
anatofuz
parents:
diff changeset
132
anatofuz
parents:
diff changeset
133 } // end namespace
anatofuz
parents:
diff changeset
134
anatofuz
parents:
diff changeset
135 TEST(CrossTranslationUnit, CanLoadFunctionDefinition) {
anatofuz
parents:
diff changeset
136 bool Success = false;
anatofuz
parents:
diff changeset
137 EXPECT_TRUE(tooling::runToolOnCode(std::make_unique<CTUAction>(&Success, 1u),
anatofuz
parents:
diff changeset
138 "int f(int);"));
anatofuz
parents:
diff changeset
139 EXPECT_TRUE(Success);
anatofuz
parents:
diff changeset
140 }
anatofuz
parents:
diff changeset
141
anatofuz
parents:
diff changeset
142 TEST(CrossTranslationUnit, RespectsLoadThreshold) {
anatofuz
parents:
diff changeset
143 bool Success = false;
anatofuz
parents:
diff changeset
144 EXPECT_TRUE(tooling::runToolOnCode(std::make_unique<CTUAction>(&Success, 0u),
anatofuz
parents:
diff changeset
145 "int f(int);"));
anatofuz
parents:
diff changeset
146 EXPECT_FALSE(Success);
anatofuz
parents:
diff changeset
147 }
anatofuz
parents:
diff changeset
148
anatofuz
parents:
diff changeset
149 TEST(CrossTranslationUnit, IndexFormatCanBeParsed) {
anatofuz
parents:
diff changeset
150 llvm::StringMap<std::string> Index;
anatofuz
parents:
diff changeset
151 Index["a"] = "/b/f1";
anatofuz
parents:
diff changeset
152 Index["c"] = "/d/f2";
anatofuz
parents:
diff changeset
153 Index["e"] = "/f/f3";
anatofuz
parents:
diff changeset
154 std::string IndexText = createCrossTUIndexString(Index);
anatofuz
parents:
diff changeset
155
anatofuz
parents:
diff changeset
156 int IndexFD;
anatofuz
parents:
diff changeset
157 llvm::SmallString<256> IndexFileName;
anatofuz
parents:
diff changeset
158 ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD,
anatofuz
parents:
diff changeset
159 IndexFileName));
anatofuz
parents:
diff changeset
160 llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD);
anatofuz
parents:
diff changeset
161 IndexFile.os() << IndexText;
anatofuz
parents:
diff changeset
162 IndexFile.os().flush();
anatofuz
parents:
diff changeset
163 EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName));
anatofuz
parents:
diff changeset
164 llvm::Expected<llvm::StringMap<std::string>> IndexOrErr =
anatofuz
parents:
diff changeset
165 parseCrossTUIndex(IndexFileName, "");
anatofuz
parents:
diff changeset
166 EXPECT_TRUE((bool)IndexOrErr);
anatofuz
parents:
diff changeset
167 llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get();
anatofuz
parents:
diff changeset
168 for (const auto &E : Index) {
anatofuz
parents:
diff changeset
169 EXPECT_TRUE(ParsedIndex.count(E.getKey()));
anatofuz
parents:
diff changeset
170 EXPECT_EQ(ParsedIndex[E.getKey()], E.getValue());
anatofuz
parents:
diff changeset
171 }
anatofuz
parents:
diff changeset
172 for (const auto &E : ParsedIndex)
anatofuz
parents:
diff changeset
173 EXPECT_TRUE(Index.count(E.getKey()));
anatofuz
parents:
diff changeset
174 }
anatofuz
parents:
diff changeset
175
anatofuz
parents:
diff changeset
176 TEST(CrossTranslationUnit, CTUDirIsHandledCorrectly) {
anatofuz
parents:
diff changeset
177 llvm::StringMap<std::string> Index;
anatofuz
parents:
diff changeset
178 Index["a"] = "/b/c/d";
anatofuz
parents:
diff changeset
179 std::string IndexText = createCrossTUIndexString(Index);
anatofuz
parents:
diff changeset
180
anatofuz
parents:
diff changeset
181 int IndexFD;
anatofuz
parents:
diff changeset
182 llvm::SmallString<256> IndexFileName;
anatofuz
parents:
diff changeset
183 ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD,
anatofuz
parents:
diff changeset
184 IndexFileName));
anatofuz
parents:
diff changeset
185 llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD);
anatofuz
parents:
diff changeset
186 IndexFile.os() << IndexText;
anatofuz
parents:
diff changeset
187 IndexFile.os().flush();
anatofuz
parents:
diff changeset
188 EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName));
anatofuz
parents:
diff changeset
189 llvm::Expected<llvm::StringMap<std::string>> IndexOrErr =
anatofuz
parents:
diff changeset
190 parseCrossTUIndex(IndexFileName, "/ctudir");
anatofuz
parents:
diff changeset
191 EXPECT_TRUE((bool)IndexOrErr);
anatofuz
parents:
diff changeset
192 llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get();
anatofuz
parents:
diff changeset
193 EXPECT_EQ(ParsedIndex["a"], "/ctudir/b/c/d");
anatofuz
parents:
diff changeset
194 }
anatofuz
parents:
diff changeset
195
anatofuz
parents:
diff changeset
196 } // end namespace cross_tu
anatofuz
parents:
diff changeset
197 } // end namespace clang