comparison clang/unittests/CrossTU/CrossTranslationUnitTest.cpp @ 207:2e18cbf3894f

LLVM12
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 08 Jun 2021 06:07:14 +0900
parents 1d019706d866
children c4bab56944e8
comparison
equal deleted inserted replaced
173:0572611fdcc8 207:2e18cbf3894f
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 // 6 //
7 //===----------------------------------------------------------------------===// 7 //===----------------------------------------------------------------------===//
8 8
9 #include "clang/CrossTU/CrossTranslationUnit.h" 9 #include "clang/CrossTU/CrossTranslationUnit.h"
10 #include "clang/AST/ASTConsumer.h"
11 #include "clang/AST/ParentMapContext.h"
10 #include "clang/Frontend/CompilerInstance.h" 12 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/AST/ASTConsumer.h"
12 #include "clang/Frontend/FrontendAction.h" 13 #include "clang/Frontend/FrontendAction.h"
13 #include "clang/Tooling/Tooling.h" 14 #include "clang/Tooling/Tooling.h"
15 #include "llvm/ADT/Optional.h"
14 #include "llvm/Support/FileSystem.h" 16 #include "llvm/Support/FileSystem.h"
15 #include "llvm/Support/Path.h" 17 #include "llvm/Support/Path.h"
16 #include "llvm/Support/ToolOutputFile.h" 18 #include "llvm/Support/ToolOutputFile.h"
17 #include "gtest/gtest.h" 19 #include "gtest/gtest.h"
18 #include <cassert> 20 #include <cassert>
25 class CTUASTConsumer : public clang::ASTConsumer { 27 class CTUASTConsumer : public clang::ASTConsumer {
26 public: 28 public:
27 explicit CTUASTConsumer(clang::CompilerInstance &CI, bool *Success) 29 explicit CTUASTConsumer(clang::CompilerInstance &CI, bool *Success)
28 : CTU(CI), Success(Success) {} 30 : CTU(CI), Success(Success) {}
29 31
30 void HandleTranslationUnit(ASTContext &Ctx) { 32 void HandleTranslationUnit(ASTContext &Ctx) override {
31 auto FindFInTU = [](const TranslationUnitDecl *TU) { 33 auto FindFInTU = [](const TranslationUnitDecl *TU) {
32 const FunctionDecl *FD = nullptr; 34 const FunctionDecl *FD = nullptr;
33 for (const Decl *D : TU->decls()) { 35 for (const Decl *D : TU->decls()) {
34 FD = dyn_cast<FunctionDecl>(D); 36 FD = dyn_cast<FunctionDecl>(D);
35 if (FD && FD->getName() == "f") 37 if (FD && FD->getName() == "f")
40 42
41 const TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl(); 43 const TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
42 const FunctionDecl *FD = FindFInTU(TU); 44 const FunctionDecl *FD = FindFInTU(TU);
43 assert(FD && FD->getName() == "f"); 45 assert(FD && FD->getName() == "f");
44 bool OrigFDHasBody = FD->hasBody(); 46 bool OrigFDHasBody = FD->hasBody();
47
48 const DynTypedNodeList ParentsBeforeImport =
49 Ctx.getParentMapContext().getParents<Decl>(*FD);
50 ASSERT_FALSE(ParentsBeforeImport.empty());
45 51
46 // Prepare the index file and the AST file. 52 // Prepare the index file and the AST file.
47 int ASTFD; 53 int ASTFD;
48 llvm::SmallString<256> ASTFileName; 54 llvm::SmallString<256> ASTFileName;
49 ASSERT_FALSE( 55 ASSERT_FALSE(
83 if (NewFDorError) { 89 if (NewFDorError) {
84 const FunctionDecl *NewFD = *NewFDorError; 90 const FunctionDecl *NewFD = *NewFDorError;
85 *Success = NewFD && NewFD->hasBody() && !OrigFDHasBody; 91 *Success = NewFD && NewFD->hasBody() && !OrigFDHasBody;
86 92
87 if (NewFD) { 93 if (NewFD) {
88 // Check GetImportedFromSourceLocation. 94 // Check parent map.
89 llvm::Optional<std::pair<SourceLocation, ASTUnit *>> SLocResult = 95 const DynTypedNodeList ParentsAfterImport =
90 CTU.getImportedFromSourceLocation(NewFD->getLocation()); 96 Ctx.getParentMapContext().getParents<Decl>(*FD);
91 EXPECT_TRUE(SLocResult); 97 const DynTypedNodeList ParentsOfImported =
92 if (SLocResult) { 98 Ctx.getParentMapContext().getParents<Decl>(*NewFD);
93 SourceLocation OrigSLoc = (*SLocResult).first; 99 EXPECT_TRUE(
94 ASTUnit *OrigUnit = (*SLocResult).second; 100 checkParentListsEq(ParentsBeforeImport, ParentsAfterImport));
95 // OrigUnit is created internally by CTU (is not the 101 EXPECT_FALSE(ParentsOfImported.empty());
96 // ASTWithDefinition).
97 TranslationUnitDecl *OrigTU =
98 OrigUnit->getASTContext().getTranslationUnitDecl();
99 const FunctionDecl *FDWithDefinition = FindFInTU(OrigTU);
100 EXPECT_TRUE(FDWithDefinition);
101 if (FDWithDefinition) {
102 EXPECT_EQ(FDWithDefinition->getName(), "f");
103 EXPECT_TRUE(FDWithDefinition->isThisDeclarationADefinition());
104 EXPECT_EQ(OrigSLoc, FDWithDefinition->getLocation());
105 }
106 }
107 } 102 }
108 } 103 }
104 }
105
106 static bool checkParentListsEq(const DynTypedNodeList &L1,
107 const DynTypedNodeList &L2) {
108 if (L1.size() != L2.size())
109 return false;
110 for (unsigned int I = 0; I < L1.size(); ++I)
111 if (L1[I] != L2[I])
112 return false;
113 return true;
109 } 114 }
110 115
111 private: 116 private:
112 CrossTranslationUnitContext CTU; 117 CrossTranslationUnitContext CTU;
113 bool *Success; 118 bool *Success;
120 125
121 protected: 126 protected:
122 std::unique_ptr<clang::ASTConsumer> 127 std::unique_ptr<clang::ASTConsumer>
123 CreateASTConsumer(clang::CompilerInstance &CI, StringRef) override { 128 CreateASTConsumer(clang::CompilerInstance &CI, StringRef) override {
124 CI.getAnalyzerOpts()->CTUImportThreshold = OverrideLimit; 129 CI.getAnalyzerOpts()->CTUImportThreshold = OverrideLimit;
130 CI.getAnalyzerOpts()->CTUImportCppThreshold = OverrideLimit;
125 return std::make_unique<CTUASTConsumer>(CI, Success); 131 return std::make_unique<CTUASTConsumer>(CI, Success);
126 } 132 }
127 133
128 private: 134 private:
129 bool *Success; 135 bool *Success;
160 llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD); 166 llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD);
161 IndexFile.os() << IndexText; 167 IndexFile.os() << IndexText;
162 IndexFile.os().flush(); 168 IndexFile.os().flush();
163 EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName)); 169 EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName));
164 llvm::Expected<llvm::StringMap<std::string>> IndexOrErr = 170 llvm::Expected<llvm::StringMap<std::string>> IndexOrErr =
165 parseCrossTUIndex(IndexFileName, ""); 171 parseCrossTUIndex(IndexFileName);
166 EXPECT_TRUE((bool)IndexOrErr); 172 EXPECT_TRUE((bool)IndexOrErr);
167 llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get(); 173 llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get();
168 for (const auto &E : Index) { 174 for (const auto &E : Index) {
169 EXPECT_TRUE(ParsedIndex.count(E.getKey())); 175 EXPECT_TRUE(ParsedIndex.count(E.getKey()));
170 EXPECT_EQ(ParsedIndex[E.getKey()], E.getValue()); 176 EXPECT_EQ(ParsedIndex[E.getKey()], E.getValue());
171 } 177 }
172 for (const auto &E : ParsedIndex) 178 for (const auto &E : ParsedIndex)
173 EXPECT_TRUE(Index.count(E.getKey())); 179 EXPECT_TRUE(Index.count(E.getKey()));
174 } 180 }
175 181
176 TEST(CrossTranslationUnit, CTUDirIsHandledCorrectly) { 182 TEST(CrossTranslationUnit, EmptyInvocationListIsNotValid) {
177 llvm::StringMap<std::string> Index; 183 auto Input = "";
178 Index["a"] = "/b/c/d"; 184
179 std::string IndexText = createCrossTUIndexString(Index); 185 llvm::Expected<InvocationListTy> Result = parseInvocationList(Input);
180 186 EXPECT_FALSE(static_cast<bool>(Result));
181 int IndexFD; 187 bool IsWrongFromatError = false;
182 llvm::SmallString<256> IndexFileName; 188 llvm::handleAllErrors(Result.takeError(), [&](IndexError &Err) {
183 ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD, 189 IsWrongFromatError =
184 IndexFileName)); 190 Err.getCode() == index_error_code::invocation_list_wrong_format;
185 llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD); 191 });
186 IndexFile.os() << IndexText; 192 EXPECT_TRUE(IsWrongFromatError);
187 IndexFile.os().flush(); 193 }
188 EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName)); 194
189 llvm::Expected<llvm::StringMap<std::string>> IndexOrErr = 195 TEST(CrossTranslationUnit, AmbiguousInvocationListIsDetected) {
190 parseCrossTUIndex(IndexFileName, "/ctudir"); 196 // The same source file occurs twice (for two different architecture) in
191 EXPECT_TRUE((bool)IndexOrErr); 197 // this test case. The disambiguation is the responsibility of the user.
192 llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get(); 198 auto Input = R"(
193 EXPECT_EQ(ParsedIndex["a"], "/ctudir/b/c/d"); 199 /tmp/main.cpp:
200 - clang++
201 - -c
202 - -m32
203 - -o
204 - main32.o
205 - /tmp/main.cpp
206 /tmp/main.cpp:
207 - clang++
208 - -c
209 - -m64
210 - -o
211 - main64.o
212 - /tmp/main.cpp
213 )";
214
215 llvm::Expected<InvocationListTy> Result = parseInvocationList(Input);
216 EXPECT_FALSE(static_cast<bool>(Result));
217 bool IsAmbiguousError = false;
218 llvm::handleAllErrors(Result.takeError(), [&](IndexError &Err) {
219 IsAmbiguousError =
220 Err.getCode() == index_error_code::invocation_list_ambiguous;
221 });
222 EXPECT_TRUE(IsAmbiguousError);
223 }
224
225 TEST(CrossTranslationUnit, SingleInvocationCanBeParsed) {
226 auto Input = R"(
227 /tmp/main.cpp:
228 - clang++
229 - /tmp/main.cpp
230 )";
231 llvm::Expected<InvocationListTy> Result = parseInvocationList(Input);
232 EXPECT_TRUE(static_cast<bool>(Result));
233
234 EXPECT_EQ(Result->size(), 1u);
235
236 auto It = Result->find("/tmp/main.cpp");
237 EXPECT_TRUE(It != Result->end());
238 EXPECT_EQ(It->getValue()[0], "clang++");
239 EXPECT_EQ(It->getValue()[1], "/tmp/main.cpp");
240 }
241
242 TEST(CrossTranslationUnit, MultipleInvocationsCanBeParsed) {
243 auto Input = R"(
244 /tmp/main.cpp:
245 - clang++
246 - /tmp/other.o
247 - /tmp/main.cpp
248 /tmp/other.cpp:
249 - g++
250 - -c
251 - -o
252 - /tmp/other.o
253 - /tmp/other.cpp
254 )";
255 llvm::Expected<InvocationListTy> Result = parseInvocationList(Input);
256 EXPECT_TRUE(static_cast<bool>(Result));
257
258 EXPECT_EQ(Result->size(), 2u);
259
260 auto It = Result->find("/tmp/main.cpp");
261 EXPECT_TRUE(It != Result->end());
262 EXPECT_EQ(It->getKey(), "/tmp/main.cpp");
263 EXPECT_EQ(It->getValue()[0], "clang++");
264 EXPECT_EQ(It->getValue()[1], "/tmp/other.o");
265 EXPECT_EQ(It->getValue()[2], "/tmp/main.cpp");
266
267 It = Result->find("/tmp/other.cpp");
268 EXPECT_TRUE(It != Result->end());
269 EXPECT_EQ(It->getValue()[0], "g++");
270 EXPECT_EQ(It->getValue()[1], "-c");
271 EXPECT_EQ(It->getValue()[2], "-o");
272 EXPECT_EQ(It->getValue()[3], "/tmp/other.o");
273 EXPECT_EQ(It->getValue()[4], "/tmp/other.cpp");
194 } 274 }
195 275
196 } // end namespace cross_tu 276 } // end namespace cross_tu
197 } // end namespace clang 277 } // end namespace clang