File: | tools/clang/lib/CrossTU/CrossTranslationUnit.cpp |
Warning: | line 239, column 38 Potential leak of memory pointed to by field 'Obj' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===--- CrossTranslationUnit.cpp - -----------------------------*- C++ -*-===// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | // | |||
10 | // This file implements the CrossTranslationUnit interface. | |||
11 | // | |||
12 | //===----------------------------------------------------------------------===// | |||
13 | #include "clang/CrossTU/CrossTranslationUnit.h" | |||
14 | #include "clang/AST/ASTImporter.h" | |||
15 | #include "clang/AST/Decl.h" | |||
16 | #include "clang/Basic/TargetInfo.h" | |||
17 | #include "clang/CrossTU/CrossTUDiagnostic.h" | |||
18 | #include "clang/Frontend/ASTUnit.h" | |||
19 | #include "clang/Frontend/CompilerInstance.h" | |||
20 | #include "clang/Frontend/FrontendDiagnostic.h" | |||
21 | #include "clang/Frontend/TextDiagnosticPrinter.h" | |||
22 | #include "clang/Index/USRGeneration.h" | |||
23 | #include "llvm/ADT/Triple.h" | |||
24 | #include "llvm/Support/ErrorHandling.h" | |||
25 | #include "llvm/Support/ManagedStatic.h" | |||
26 | #include "llvm/Support/Path.h" | |||
27 | #include "llvm/Support/raw_ostream.h" | |||
28 | #include <fstream> | |||
29 | #include <sstream> | |||
30 | ||||
31 | namespace clang { | |||
32 | namespace cross_tu { | |||
33 | ||||
34 | namespace { | |||
35 | // FIXME: This class is will be removed after the transition to llvm::Error. | |||
36 | class IndexErrorCategory : public std::error_category { | |||
37 | public: | |||
38 | const char *name() const noexcept override { return "clang.index"; } | |||
39 | ||||
40 | std::string message(int Condition) const override { | |||
41 | switch (static_cast<index_error_code>(Condition)) { | |||
42 | case index_error_code::unspecified: | |||
43 | return "An unknown error has occurred."; | |||
44 | case index_error_code::missing_index_file: | |||
45 | return "The index file is missing."; | |||
46 | case index_error_code::invalid_index_format: | |||
47 | return "Invalid index file format."; | |||
48 | case index_error_code::multiple_definitions: | |||
49 | return "Multiple definitions in the index file."; | |||
50 | case index_error_code::missing_definition: | |||
51 | return "Missing definition from the index file."; | |||
52 | case index_error_code::failed_import: | |||
53 | return "Failed to import the definition."; | |||
54 | case index_error_code::failed_to_get_external_ast: | |||
55 | return "Failed to load external AST source."; | |||
56 | case index_error_code::failed_to_generate_usr: | |||
57 | return "Failed to generate USR."; | |||
58 | } | |||
59 | llvm_unreachable("Unrecognized index_error_code.")::llvm::llvm_unreachable_internal("Unrecognized index_error_code." , "/build/llvm-toolchain-snapshot-7~svn338205/tools/clang/lib/CrossTU/CrossTranslationUnit.cpp" , 59); | |||
60 | } | |||
61 | }; | |||
62 | ||||
63 | static llvm::ManagedStatic<IndexErrorCategory> Category; | |||
64 | } // end anonymous namespace | |||
65 | ||||
66 | char IndexError::ID; | |||
67 | ||||
68 | void IndexError::log(raw_ostream &OS) const { | |||
69 | OS << Category->message(static_cast<int>(Code)) << '\n'; | |||
70 | } | |||
71 | ||||
72 | std::error_code IndexError::convertToErrorCode() const { | |||
73 | return std::error_code(static_cast<int>(Code), *Category); | |||
74 | } | |||
75 | ||||
76 | llvm::Expected<llvm::StringMap<std::string>> | |||
77 | parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir) { | |||
78 | std::ifstream ExternalFnMapFile(IndexPath); | |||
79 | if (!ExternalFnMapFile) | |||
80 | return llvm::make_error<IndexError>(index_error_code::missing_index_file, | |||
81 | IndexPath.str()); | |||
82 | ||||
83 | llvm::StringMap<std::string> Result; | |||
84 | std::string Line; | |||
85 | unsigned LineNo = 1; | |||
86 | while (std::getline(ExternalFnMapFile, Line)) { | |||
87 | const size_t Pos = Line.find(" "); | |||
88 | if (Pos > 0 && Pos != std::string::npos) { | |||
89 | StringRef LineRef{Line}; | |||
90 | StringRef FunctionLookupName = LineRef.substr(0, Pos); | |||
91 | if (Result.count(FunctionLookupName)) | |||
92 | return llvm::make_error<IndexError>( | |||
93 | index_error_code::multiple_definitions, IndexPath.str(), LineNo); | |||
94 | StringRef FileName = LineRef.substr(Pos + 1); | |||
95 | SmallString<256> FilePath = CrossTUDir; | |||
96 | llvm::sys::path::append(FilePath, FileName); | |||
97 | Result[FunctionLookupName] = FilePath.str().str(); | |||
98 | } else | |||
99 | return llvm::make_error<IndexError>( | |||
100 | index_error_code::invalid_index_format, IndexPath.str(), LineNo); | |||
101 | LineNo++; | |||
102 | } | |||
103 | return Result; | |||
104 | } | |||
105 | ||||
106 | std::string | |||
107 | createCrossTUIndexString(const llvm::StringMap<std::string> &Index) { | |||
108 | std::ostringstream Result; | |||
109 | for (const auto &E : Index) | |||
110 | Result << E.getKey().str() << " " << E.getValue() << '\n'; | |||
111 | return Result.str(); | |||
112 | } | |||
113 | ||||
114 | CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI) | |||
115 | : CI(CI), Context(CI.getASTContext()) {} | |||
116 | ||||
117 | CrossTranslationUnitContext::~CrossTranslationUnitContext() {} | |||
118 | ||||
119 | std::string CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) { | |||
120 | SmallString<128> DeclUSR; | |||
121 | bool Ret = index::generateUSRForDecl(ND, DeclUSR); (void)Ret; | |||
122 | assert(!Ret && "Unable to generate USR")(static_cast <bool> (!Ret && "Unable to generate USR" ) ? void (0) : __assert_fail ("!Ret && \"Unable to generate USR\"" , "/build/llvm-toolchain-snapshot-7~svn338205/tools/clang/lib/CrossTU/CrossTranslationUnit.cpp" , 122, __extension__ __PRETTY_FUNCTION__)); | |||
123 | return DeclUSR.str(); | |||
124 | } | |||
125 | ||||
126 | /// Recursively visits the function decls of a DeclContext, and looks up a | |||
127 | /// function based on USRs. | |||
128 | const FunctionDecl * | |||
129 | CrossTranslationUnitContext::findFunctionInDeclContext(const DeclContext *DC, | |||
130 | StringRef LookupFnName) { | |||
131 | assert(DC && "Declaration Context must not be null")(static_cast <bool> (DC && "Declaration Context must not be null" ) ? void (0) : __assert_fail ("DC && \"Declaration Context must not be null\"" , "/build/llvm-toolchain-snapshot-7~svn338205/tools/clang/lib/CrossTU/CrossTranslationUnit.cpp" , 131, __extension__ __PRETTY_FUNCTION__)); | |||
132 | for (const Decl *D : DC->decls()) { | |||
133 | const auto *SubDC = dyn_cast<DeclContext>(D); | |||
134 | if (SubDC) | |||
135 | if (const auto *FD = findFunctionInDeclContext(SubDC, LookupFnName)) | |||
136 | return FD; | |||
137 | ||||
138 | const auto *ND = dyn_cast<FunctionDecl>(D); | |||
139 | const FunctionDecl *ResultDecl; | |||
140 | if (!ND || !ND->hasBody(ResultDecl)) | |||
141 | continue; | |||
142 | if (getLookupName(ResultDecl) != LookupFnName) | |||
143 | continue; | |||
144 | return ResultDecl; | |||
145 | } | |||
146 | return nullptr; | |||
147 | } | |||
148 | ||||
149 | llvm::Expected<const FunctionDecl *> | |||
150 | CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD, | |||
151 | StringRef CrossTUDir, | |||
152 | StringRef IndexName) { | |||
153 | assert(!FD->hasBody() && "FD has a definition in current translation unit!")(static_cast <bool> (!FD->hasBody() && "FD has a definition in current translation unit!" ) ? void (0) : __assert_fail ("!FD->hasBody() && \"FD has a definition in current translation unit!\"" , "/build/llvm-toolchain-snapshot-7~svn338205/tools/clang/lib/CrossTU/CrossTranslationUnit.cpp" , 153, __extension__ __PRETTY_FUNCTION__)); | |||
154 | const std::string LookupFnName = getLookupName(FD); | |||
155 | if (LookupFnName.empty()) | |||
| ||||
156 | return llvm::make_error<IndexError>( | |||
157 | index_error_code::failed_to_generate_usr); | |||
158 | llvm::Expected<ASTUnit *> ASTUnitOrError = | |||
159 | loadExternalAST(LookupFnName, CrossTUDir, IndexName); | |||
160 | if (!ASTUnitOrError) | |||
161 | return ASTUnitOrError.takeError(); | |||
162 | ASTUnit *Unit = *ASTUnitOrError; | |||
163 | if (!Unit) | |||
164 | return llvm::make_error<IndexError>( | |||
165 | index_error_code::failed_to_get_external_ast); | |||
166 | assert(&Unit->getFileManager() ==(static_cast <bool> (&Unit->getFileManager() == & Unit->getASTContext().getSourceManager().getFileManager()) ? void (0) : __assert_fail ("&Unit->getFileManager() == &Unit->getASTContext().getSourceManager().getFileManager()" , "/build/llvm-toolchain-snapshot-7~svn338205/tools/clang/lib/CrossTU/CrossTranslationUnit.cpp" , 167, __extension__ __PRETTY_FUNCTION__)) | |||
167 | &Unit->getASTContext().getSourceManager().getFileManager())(static_cast <bool> (&Unit->getFileManager() == & Unit->getASTContext().getSourceManager().getFileManager()) ? void (0) : __assert_fail ("&Unit->getFileManager() == &Unit->getASTContext().getSourceManager().getFileManager()" , "/build/llvm-toolchain-snapshot-7~svn338205/tools/clang/lib/CrossTU/CrossTranslationUnit.cpp" , 167, __extension__ __PRETTY_FUNCTION__)); | |||
168 | ||||
169 | TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl(); | |||
170 | if (const FunctionDecl *ResultDecl = | |||
171 | findFunctionInDeclContext(TU, LookupFnName)) | |||
172 | return importDefinition(ResultDecl); | |||
173 | return llvm::make_error<IndexError>(index_error_code::failed_import); | |||
174 | } | |||
175 | ||||
176 | void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) { | |||
177 | switch (IE.getCode()) { | |||
178 | case index_error_code::missing_index_file: | |||
179 | Context.getDiagnostics().Report(diag::err_fe_error_opening) | |||
180 | << IE.getFileName() << "required by the CrossTU functionality"; | |||
181 | break; | |||
182 | case index_error_code::invalid_index_format: | |||
183 | Context.getDiagnostics().Report(diag::err_fnmap_parsing) | |||
184 | << IE.getFileName() << IE.getLineNum(); | |||
185 | break; | |||
186 | case index_error_code::multiple_definitions: | |||
187 | Context.getDiagnostics().Report(diag::err_multiple_def_index) | |||
188 | << IE.getLineNum(); | |||
189 | break; | |||
190 | default: | |||
191 | break; | |||
192 | } | |||
193 | } | |||
194 | ||||
195 | llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( | |||
196 | StringRef LookupName, StringRef CrossTUDir, StringRef IndexName) { | |||
197 | // FIXME: The current implementation only supports loading functions with | |||
198 | // a lookup name from a single translation unit. If multiple | |||
199 | // translation units contains functions with the same lookup name an | |||
200 | // error will be returned. | |||
201 | ASTUnit *Unit = nullptr; | |||
202 | auto FnUnitCacheEntry = FunctionASTUnitMap.find(LookupName); | |||
203 | if (FnUnitCacheEntry == FunctionASTUnitMap.end()) { | |||
204 | if (FunctionFileMap.empty()) { | |||
205 | SmallString<256> IndexFile = CrossTUDir; | |||
206 | if (llvm::sys::path::is_absolute(IndexName)) | |||
207 | IndexFile = IndexName; | |||
208 | else | |||
209 | llvm::sys::path::append(IndexFile, IndexName); | |||
210 | llvm::Expected<llvm::StringMap<std::string>> IndexOrErr = | |||
211 | parseCrossTUIndex(IndexFile, CrossTUDir); | |||
212 | if (IndexOrErr) | |||
213 | FunctionFileMap = *IndexOrErr; | |||
214 | else | |||
215 | return IndexOrErr.takeError(); | |||
216 | } | |||
217 | ||||
218 | auto It = FunctionFileMap.find(LookupName); | |||
219 | if (It == FunctionFileMap.end()) | |||
220 | return llvm::make_error<IndexError>(index_error_code::missing_definition); | |||
221 | StringRef ASTFileName = It->second; | |||
222 | auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName); | |||
223 | if (ASTCacheEntry == FileASTUnitMap.end()) { | |||
224 | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); | |||
225 | TextDiagnosticPrinter *DiagClient = | |||
226 | new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); | |||
227 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); | |||
228 | IntrusiveRefCntPtr<DiagnosticsEngine> Diags( | |||
229 | new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient)); | |||
230 | ||||
231 | std::unique_ptr<ASTUnit> LoadedUnit(ASTUnit::LoadFromASTFile( | |||
232 | ASTFileName, CI.getPCHContainerOperations()->getRawReader(), | |||
233 | ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts())); | |||
234 | Unit = LoadedUnit.get(); | |||
235 | FileASTUnitMap[ASTFileName] = std::move(LoadedUnit); | |||
236 | } else { | |||
237 | Unit = ASTCacheEntry->second.get(); | |||
238 | } | |||
239 | FunctionASTUnitMap[LookupName] = Unit; | |||
| ||||
240 | } else { | |||
241 | Unit = FnUnitCacheEntry->second; | |||
242 | } | |||
243 | return Unit; | |||
244 | } | |||
245 | ||||
246 | llvm::Expected<const FunctionDecl *> | |||
247 | CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) { | |||
248 | ASTImporter &Importer = getOrCreateASTImporter(FD->getASTContext()); | |||
249 | auto *ToDecl = | |||
250 | cast<FunctionDecl>(Importer.Import(const_cast<FunctionDecl *>(FD))); | |||
251 | assert(ToDecl->hasBody())(static_cast <bool> (ToDecl->hasBody()) ? void (0) : __assert_fail ("ToDecl->hasBody()", "/build/llvm-toolchain-snapshot-7~svn338205/tools/clang/lib/CrossTU/CrossTranslationUnit.cpp" , 251, __extension__ __PRETTY_FUNCTION__)); | |||
252 | assert(FD->hasBody() && "Functions already imported should have body.")(static_cast <bool> (FD->hasBody() && "Functions already imported should have body." ) ? void (0) : __assert_fail ("FD->hasBody() && \"Functions already imported should have body.\"" , "/build/llvm-toolchain-snapshot-7~svn338205/tools/clang/lib/CrossTU/CrossTranslationUnit.cpp" , 252, __extension__ __PRETTY_FUNCTION__)); | |||
253 | return ToDecl; | |||
254 | } | |||
255 | ||||
256 | ASTImporter & | |||
257 | CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) { | |||
258 | auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl()); | |||
259 | if (I != ASTUnitImporterMap.end()) | |||
260 | return *I->second; | |||
261 | ASTImporter *NewImporter = | |||
262 | new ASTImporter(Context, Context.getSourceManager().getFileManager(), | |||
263 | From, From.getSourceManager().getFileManager(), false); | |||
264 | ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter); | |||
265 | return *NewImporter; | |||
266 | } | |||
267 | ||||
268 | } // namespace cross_tu | |||
269 | } // namespace clang |