Mercurial > hg > CbC > CbC_llvm
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 |