1 //===--- CrossTranslationUnit.h - -------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file provides an interface to load binary AST dumps on demand. This 10 // feature can be utilized for tools that require cross translation unit 11 // support. 12 // 13 //===----------------------------------------------------------------------===// 14 #ifndef LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H 15 #define LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H 16 17 #include "clang/AST/ASTImporterSharedState.h" 18 #include "clang/Basic/LLVM.h" 19 #include "llvm/ADT/DenseMap.h" 20 #include "llvm/ADT/SmallPtrSet.h" 21 #include "llvm/ADT/StringMap.h" 22 #include "llvm/Support/Error.h" 23 24 namespace clang { 25 class CompilerInstance; 26 class ASTContext; 27 class ASTImporter; 28 class ASTUnit; 29 class DeclContext; 30 class FunctionDecl; 31 class VarDecl; 32 class NamedDecl; 33 class TranslationUnitDecl; 34 35 namespace cross_tu { 36 37 enum class index_error_code { 38 unspecified = 1, 39 missing_index_file, 40 invalid_index_format, 41 multiple_definitions, 42 missing_definition, 43 failed_import, 44 failed_to_get_external_ast, 45 failed_to_generate_usr, 46 triple_mismatch, 47 lang_mismatch, 48 lang_dialect_mismatch, 49 load_threshold_reached 50 }; 51 52 class IndexError : public llvm::ErrorInfo<IndexError> { 53 public: 54 static char ID; 55 IndexError(index_error_code C) : Code(C), LineNo(0) {} 56 IndexError(index_error_code C, std::string FileName, int LineNo = 0) 57 : Code(C), FileName(std::move(FileName)), LineNo(LineNo) {} 58 IndexError(index_error_code C, std::string FileName, std::string TripleToName, 59 std::string TripleFromName) 60 : Code(C), FileName(std::move(FileName)), 61 TripleToName(std::move(TripleToName)), 62 TripleFromName(std::move(TripleFromName)) {} 63 void log(raw_ostream &OS) const override; 64 std::error_code convertToErrorCode() const override; 65 index_error_code getCode() const { return Code; } 66 int getLineNum() const { return LineNo; } 67 std::string getFileName() const { return FileName; } 68 std::string getTripleToName() const { return TripleToName; } 69 std::string getTripleFromName() const { return TripleFromName; } 70 71 private: 72 index_error_code Code; 73 std::string FileName; 74 int LineNo; 75 std::string TripleToName; 76 std::string TripleFromName; 77 }; 78 79 /// This function parses an index file that determines which 80 /// translation unit contains which definition. 81 /// 82 /// The index file format is the following: 83 /// each line consists of an USR and a filepath separated by a space. 84 /// 85 /// \return Returns a map where the USR is the key and the filepath is the value 86 /// or an error. 87 llvm::Expected<llvm::StringMap<std::string>> 88 parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir); 89 90 std::string createCrossTUIndexString(const llvm::StringMap<std::string> &Index); 91 92 // Returns true if the variable or any field of a record variable is const. 93 bool containsConst(const VarDecl *VD, const ASTContext &ACtx); 94 95 /// This class is used for tools that requires cross translation 96 /// unit capability. 97 /// 98 /// This class can load definitions from external AST files. 99 /// The loaded definition will be merged back to the original AST using the 100 /// AST Importer. 101 /// In order to use this class, an index file is required that describes 102 /// the locations of the AST files for each definition. 103 /// 104 /// Note that this class also implements caching. 105 class CrossTranslationUnitContext { 106 public: 107 CrossTranslationUnitContext(CompilerInstance &CI); 108 ~CrossTranslationUnitContext(); 109 110 /// This function loads a function or variable definition from an 111 /// external AST file and merges it into the original AST. 112 /// 113 /// This method should only be used on functions that have no definitions or 114 /// variables that have no initializer in 115 /// the current translation unit. A function definition with the same 116 /// declaration will be looked up in the index file which should be in the 117 /// \p CrossTUDir directory, called \p IndexName. In case the declaration is 118 /// found in the index the corresponding AST file will be loaded and the 119 /// definition will be merged into the original AST using the AST Importer. 120 /// 121 /// \return The declaration with the definition will be returned. 122 /// If no suitable definition is found in the index file or multiple 123 /// definitions found error will be returned. 124 /// 125 /// Note that the AST files should also be in the \p CrossTUDir. 126 llvm::Expected<const FunctionDecl *> 127 getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir, 128 StringRef IndexName, bool DisplayCTUProgress = false); 129 llvm::Expected<const VarDecl *> 130 getCrossTUDefinition(const VarDecl *VD, StringRef CrossTUDir, 131 StringRef IndexName, bool DisplayCTUProgress = false); 132 133 /// This function loads a definition from an external AST file. 134 /// 135 /// A definition with the same declaration will be looked up in the 136 /// index file which should be in the \p CrossTUDir directory, called 137 /// \p IndexName. In case the declaration is found in the index the 138 /// corresponding AST file will be loaded. If the number of TUs imported 139 /// reaches \p CTULoadTreshold, no loading is performed. 140 /// 141 /// \return Returns a pointer to the ASTUnit that contains the definition of 142 /// the looked up name or an Error. 143 /// The returned pointer is never a nullptr. 144 /// 145 /// Note that the AST files should also be in the \p CrossTUDir. 146 llvm::Expected<ASTUnit *> loadExternalAST(StringRef LookupName, 147 StringRef CrossTUDir, 148 StringRef IndexName, 149 bool DisplayCTUProgress = false); 150 151 /// This function merges a definition from a separate AST Unit into 152 /// the current one which was created by the compiler instance that 153 /// was passed to the constructor. 154 /// 155 /// \return Returns the resulting definition or an error. 156 llvm::Expected<const FunctionDecl *> importDefinition(const FunctionDecl *FD); 157 llvm::Expected<const VarDecl *> importDefinition(const VarDecl *VD); 158 159 /// Get a name to identify a named decl. 160 static std::string getLookupName(const NamedDecl *ND); 161 162 /// Emit diagnostics for the user for potential configuration errors. 163 void emitCrossTUDiagnostics(const IndexError &IE); 164 165 private: 166 void lazyInitImporterSharedSt(TranslationUnitDecl *ToTU); 167 ASTImporter &getOrCreateASTImporter(ASTContext &From); 168 template <typename T> 169 llvm::Expected<const T *> getCrossTUDefinitionImpl(const T *D, 170 StringRef CrossTUDir, 171 StringRef IndexName, 172 bool DisplayCTUProgress); 173 template <typename T> 174 const T *findDefInDeclContext(const DeclContext *DC, 175 StringRef LookupName); 176 template <typename T> 177 llvm::Expected<const T *> importDefinitionImpl(const T *D); 178 179 llvm::StringMap<std::unique_ptr<clang::ASTUnit>> FileASTUnitMap; 180 llvm::StringMap<clang::ASTUnit *> NameASTUnitMap; 181 llvm::StringMap<std::string> NameFileMap; 182 llvm::DenseMap<TranslationUnitDecl *, std::unique_ptr<ASTImporter>> 183 ASTUnitImporterMap; 184 CompilerInstance &CI; 185 ASTContext &Context; 186 std::shared_ptr<ASTImporterSharedState> ImporterSharedSt; 187 /// \p CTULoadTreshold should serve as an upper limit to the number of TUs 188 /// imported in order to reduce the memory footprint of CTU analysis. 189 const unsigned CTULoadThreshold; 190 unsigned NumASTLoaded{0u}; 191 }; 192 193 } // namespace cross_tu 194 } // namespace clang 195 196 #endif // LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H 197