1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "clang/CrossTU/CrossTranslationUnit.h" |
10 | #include "clang/AST/ASTConsumer.h" |
11 | #include "clang/Frontend/FrontendAction.h" |
12 | #include "clang/Tooling/Tooling.h" |
13 | #include "llvm/Support/FileSystem.h" |
14 | #include "llvm/Support/Path.h" |
15 | #include "llvm/Support/ToolOutputFile.h" |
16 | #include "gtest/gtest.h" |
17 | #include <cassert> |
18 | |
19 | namespace clang { |
20 | namespace cross_tu { |
21 | |
22 | namespace { |
23 | |
24 | class CTUASTConsumer : public clang::ASTConsumer { |
25 | public: |
26 | explicit CTUASTConsumer(clang::CompilerInstance &CI, bool *Success) |
27 | : CTU(CI), Success(Success) {} |
28 | |
29 | void HandleTranslationUnit(ASTContext &Ctx) { |
30 | const TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl(); |
31 | const FunctionDecl *FD = nullptr; |
32 | for (const Decl *D : TU->decls()) { |
33 | FD = dyn_cast<FunctionDecl>(D); |
34 | if (FD && FD->getName() == "f") |
35 | break; |
36 | } |
37 | (0) . __assert_fail ("FD && FD->getName() == \"f\"", "/home/seafit/code_projects/clang_source/clang/unittests/CrossTU/CrossTranslationUnitTest.cpp", 37, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(FD && FD->getName() == "f"); |
38 | bool OrigFDHasBody = FD->hasBody(); |
39 | |
40 | |
41 | int ASTFD; |
42 | llvm::SmallString<256> ASTFileName; |
43 | ASSERT_FALSE( |
44 | llvm::sys::fs::createTemporaryFile("f_ast", "ast", ASTFD, ASTFileName)); |
45 | llvm::ToolOutputFile ASTFile(ASTFileName, ASTFD); |
46 | |
47 | int IndexFD; |
48 | llvm::SmallString<256> IndexFileName; |
49 | ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD, |
50 | IndexFileName)); |
51 | llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD); |
52 | IndexFile.os() << "c:@F@f#I# " << ASTFileName << "\n"; |
53 | IndexFile.os().flush(); |
54 | EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName)); |
55 | |
56 | StringRef SourceText = "int f(int) { return 0; }\n"; |
57 | |
58 | int SourceFD; |
59 | llvm::SmallString<256> SourceFileName; |
60 | ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("input", "cpp", SourceFD, |
61 | SourceFileName)); |
62 | llvm::ToolOutputFile SourceFile(SourceFileName, SourceFD); |
63 | SourceFile.os() << SourceText; |
64 | SourceFile.os().flush(); |
65 | EXPECT_TRUE(llvm::sys::fs::exists(SourceFileName)); |
66 | |
67 | std::unique_ptr<ASTUnit> ASTWithDefinition = |
68 | tooling::buildASTFromCode(SourceText, SourceFileName); |
69 | ASTWithDefinition->Save(ASTFileName.str()); |
70 | EXPECT_TRUE(llvm::sys::fs::exists(ASTFileName)); |
71 | |
72 | |
73 | llvm::Expected<const FunctionDecl *> NewFDorError = |
74 | CTU.getCrossTUDefinition(FD, "", IndexFileName); |
75 | EXPECT_TRUE((bool)NewFDorError); |
76 | const FunctionDecl *NewFD = *NewFDorError; |
77 | |
78 | *Success = NewFD && NewFD->hasBody() && !OrigFDHasBody; |
79 | } |
80 | |
81 | private: |
82 | CrossTranslationUnitContext CTU; |
83 | bool *Success; |
84 | }; |
85 | |
86 | class CTUAction : public clang::ASTFrontendAction { |
87 | public: |
88 | CTUAction(bool *Success) : Success(Success) {} |
89 | |
90 | protected: |
91 | std::unique_ptr<clang::ASTConsumer> |
92 | CreateASTConsumer(clang::CompilerInstance &CI, StringRef) override { |
93 | return llvm::make_unique<CTUASTConsumer>(CI, Success); |
94 | } |
95 | |
96 | private: |
97 | bool *Success; |
98 | }; |
99 | |
100 | } |
101 | |
102 | TEST(CrossTranslationUnit, CanLoadFunctionDefinition) { |
103 | bool Success = false; |
104 | EXPECT_TRUE(tooling::runToolOnCode(new CTUAction(&Success), "int f(int);")); |
105 | EXPECT_TRUE(Success); |
106 | } |
107 | |
108 | TEST(CrossTranslationUnit, IndexFormatCanBeParsed) { |
109 | llvm::StringMap<std::string> Index; |
110 | Index["a"] = "/b/f1"; |
111 | Index["c"] = "/d/f2"; |
112 | Index["e"] = "/f/f3"; |
113 | std::string IndexText = createCrossTUIndexString(Index); |
114 | |
115 | int IndexFD; |
116 | llvm::SmallString<256> IndexFileName; |
117 | ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD, |
118 | IndexFileName)); |
119 | llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD); |
120 | IndexFile.os() << IndexText; |
121 | IndexFile.os().flush(); |
122 | EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName)); |
123 | llvm::Expected<llvm::StringMap<std::string>> IndexOrErr = |
124 | parseCrossTUIndex(IndexFileName, ""); |
125 | EXPECT_TRUE((bool)IndexOrErr); |
126 | llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get(); |
127 | for (const auto &E : Index) { |
128 | EXPECT_TRUE(ParsedIndex.count(E.getKey())); |
129 | EXPECT_EQ(ParsedIndex[E.getKey()], E.getValue()); |
130 | } |
131 | for (const auto &E : ParsedIndex) |
132 | EXPECT_TRUE(Index.count(E.getKey())); |
133 | } |
134 | |
135 | TEST(CrossTranslationUnit, CTUDirIsHandledCorrectly) { |
136 | llvm::StringMap<std::string> Index; |
137 | Index["a"] = "/b/c/d"; |
138 | std::string IndexText = createCrossTUIndexString(Index); |
139 | |
140 | int IndexFD; |
141 | llvm::SmallString<256> IndexFileName; |
142 | ASSERT_FALSE(llvm::sys::fs::createTemporaryFile("index", "txt", IndexFD, |
143 | IndexFileName)); |
144 | llvm::ToolOutputFile IndexFile(IndexFileName, IndexFD); |
145 | IndexFile.os() << IndexText; |
146 | IndexFile.os().flush(); |
147 | EXPECT_TRUE(llvm::sys::fs::exists(IndexFileName)); |
148 | llvm::Expected<llvm::StringMap<std::string>> IndexOrErr = |
149 | parseCrossTUIndex(IndexFileName, "/ctudir"); |
150 | EXPECT_TRUE((bool)IndexOrErr); |
151 | llvm::StringMap<std::string> ParsedIndex = IndexOrErr.get(); |
152 | EXPECT_EQ(ParsedIndex["a"], "/ctudir/b/c/d"); |
153 | } |
154 | |
155 | } |
156 | } |
157 | |