Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:52

0001 //===--- CrossTranslationUnit.h - -------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  This file provides an interface to load binary AST dumps on demand. This
0010 //  feature can be utilized for tools that require cross translation unit
0011 //  support.
0012 //
0013 //===----------------------------------------------------------------------===//
0014 #ifndef LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H
0015 #define LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H
0016 
0017 #include "clang/AST/ASTImporterSharedState.h"
0018 #include "clang/Analysis/MacroExpansionContext.h"
0019 #include "clang/Basic/LLVM.h"
0020 #include "llvm/ADT/DenseMap.h"
0021 #include "llvm/ADT/SmallPtrSet.h"
0022 #include "llvm/ADT/StringMap.h"
0023 #include "llvm/Support/Error.h"
0024 #include "llvm/Support/Path.h"
0025 #include <optional>
0026 
0027 namespace clang {
0028 class CompilerInstance;
0029 class ASTContext;
0030 class ASTImporter;
0031 class ASTUnit;
0032 class DeclContext;
0033 class FunctionDecl;
0034 class VarDecl;
0035 class NamedDecl;
0036 class TranslationUnitDecl;
0037 
0038 namespace cross_tu {
0039 
0040 enum class index_error_code {
0041   success = 0,
0042   unspecified = 1,
0043   missing_index_file,
0044   invalid_index_format,
0045   multiple_definitions,
0046   missing_definition,
0047   failed_import,
0048   failed_to_get_external_ast,
0049   failed_to_generate_usr,
0050   triple_mismatch,
0051   lang_mismatch,
0052   lang_dialect_mismatch,
0053   load_threshold_reached,
0054   invocation_list_ambiguous,
0055   invocation_list_file_not_found,
0056   invocation_list_empty,
0057   invocation_list_wrong_format,
0058   invocation_list_lookup_unsuccessful
0059 };
0060 
0061 class IndexError : public llvm::ErrorInfo<IndexError> {
0062 public:
0063   static char ID;
0064   IndexError(index_error_code C) : Code(C), LineNo(0) {}
0065   IndexError(index_error_code C, std::string FileName, int LineNo = 0)
0066       : Code(C), FileName(std::move(FileName)), LineNo(LineNo) {}
0067   IndexError(index_error_code C, std::string FileName, std::string TripleToName,
0068              std::string TripleFromName)
0069       : Code(C), FileName(std::move(FileName)),
0070         TripleToName(std::move(TripleToName)),
0071         TripleFromName(std::move(TripleFromName)) {}
0072   void log(raw_ostream &OS) const override;
0073   std::error_code convertToErrorCode() const override;
0074   index_error_code getCode() const { return Code; }
0075   int getLineNum() const { return LineNo; }
0076   std::string getFileName() const { return FileName; }
0077   std::string getTripleToName() const { return TripleToName; }
0078   std::string getTripleFromName() const { return TripleFromName; }
0079 
0080 private:
0081   index_error_code Code;
0082   std::string FileName;
0083   int LineNo;
0084   std::string TripleToName;
0085   std::string TripleFromName;
0086 };
0087 
0088 /// This function parses an index file that determines which
0089 /// translation unit contains which definition. The IndexPath is not prefixed
0090 /// with CTUDir, so an absolute path is expected for consistent results.
0091 ///
0092 /// The index file format is the following:
0093 /// each line consists of an USR and a filepath separated by a space.
0094 ///
0095 /// \return Returns a map where the USR is the key and the filepath is the value
0096 ///         or an error.
0097 llvm::Expected<llvm::StringMap<std::string>>
0098 parseCrossTUIndex(StringRef IndexPath);
0099 
0100 std::string createCrossTUIndexString(const llvm::StringMap<std::string> &Index);
0101 
0102 using InvocationListTy = llvm::StringMap<llvm::SmallVector<std::string, 32>>;
0103 /// Parse the YAML formatted invocation list file content \p FileContent.
0104 /// The format is expected to be a mapping from absolute source file
0105 /// paths in the filesystem to a list of command-line parts, which
0106 /// constitute the invocation needed to compile that file. That invocation
0107 /// will be used to produce the AST of the TU.
0108 llvm::Expected<InvocationListTy> parseInvocationList(
0109     StringRef FileContent,
0110     llvm::sys::path::Style PathStyle = llvm::sys::path::Style::posix);
0111 
0112 /// Returns true if it makes sense to import a foreign variable definition.
0113 /// For instance, we don't want to import variables that have non-trivial types
0114 /// because the constructor might have side-effects.
0115 bool shouldImport(const VarDecl *VD, const ASTContext &ACtx);
0116 
0117 /// This class is used for tools that requires cross translation
0118 ///        unit capability.
0119 ///
0120 /// This class can load definitions from external AST sources.
0121 /// The loaded definition will be merged back to the original AST using the
0122 /// AST Importer.
0123 /// In order to use this class, an index file is required that describes
0124 /// the locations of the AST files for each definition.
0125 ///
0126 /// Note that this class also implements caching.
0127 class CrossTranslationUnitContext {
0128 public:
0129   CrossTranslationUnitContext(CompilerInstance &CI);
0130   ~CrossTranslationUnitContext();
0131 
0132   /// This function loads a function or variable definition from an
0133   ///        external AST file and merges it into the original AST.
0134   ///
0135   /// This method should only be used on functions that have no definitions or
0136   /// variables that have no initializer in
0137   /// the current translation unit. A function definition with the same
0138   /// declaration will be looked up in the index file which should be in the
0139   /// \p CrossTUDir directory, called \p IndexName. In case the declaration is
0140   /// found in the index the corresponding AST will be loaded and the
0141   /// definition will be merged into the original AST using the AST Importer.
0142   ///
0143   /// \return The declaration with the definition will be returned.
0144   /// If no suitable definition is found in the index file or multiple
0145   /// definitions found error will be returned.
0146   ///
0147   /// Note that the AST files should also be in the \p CrossTUDir.
0148   llvm::Expected<const FunctionDecl *>
0149   getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir,
0150                        StringRef IndexName, bool DisplayCTUProgress = false);
0151   llvm::Expected<const VarDecl *>
0152   getCrossTUDefinition(const VarDecl *VD, StringRef CrossTUDir,
0153                        StringRef IndexName, bool DisplayCTUProgress = false);
0154 
0155   /// This function loads a definition from an external AST file.
0156   ///
0157   /// A definition with the same declaration will be looked up in the
0158   /// index file which should be in the \p CrossTUDir directory, called
0159   /// \p IndexName. In case the declaration is found in the index the
0160   /// corresponding AST will be loaded. If the number of TUs imported
0161   /// reaches \p CTULoadTreshold, no loading is performed.
0162   ///
0163   /// \return Returns a pointer to the ASTUnit that contains the definition of
0164   /// the looked up name or an Error.
0165   /// The returned pointer is never a nullptr.
0166   ///
0167   /// Note that the AST files should also be in the \p CrossTUDir.
0168   llvm::Expected<ASTUnit *> loadExternalAST(StringRef LookupName,
0169                                             StringRef CrossTUDir,
0170                                             StringRef IndexName,
0171                                             bool DisplayCTUProgress = false);
0172 
0173   /// This function merges a definition from a separate AST Unit into
0174   ///        the current one which was created by the compiler instance that
0175   ///        was passed to the constructor.
0176   ///
0177   /// \return Returns the resulting definition or an error.
0178   llvm::Expected<const FunctionDecl *> importDefinition(const FunctionDecl *FD,
0179                                                         ASTUnit *Unit);
0180   llvm::Expected<const VarDecl *> importDefinition(const VarDecl *VD,
0181                                                    ASTUnit *Unit);
0182 
0183   /// Get a name to identify a named decl.
0184   static std::optional<std::string> getLookupName(const NamedDecl *ND);
0185 
0186   /// Emit diagnostics for the user for potential configuration errors.
0187   void emitCrossTUDiagnostics(const IndexError &IE);
0188 
0189   /// Returns the MacroExpansionContext for the imported TU to which the given
0190   /// source-location corresponds.
0191   /// \p ToLoc Source location in the imported-to AST.
0192   /// \note If any error happens such as \p ToLoc is a non-imported
0193   ///       source-location, empty is returned.
0194   /// \note Macro expansion tracking for imported TUs is not implemented yet.
0195   ///       It returns empty unconditionally.
0196   std::optional<clang::MacroExpansionContext>
0197   getMacroExpansionContextForSourceLocation(
0198       const clang::SourceLocation &ToLoc) const;
0199 
0200   /// Returns true if the given Decl is newly created during the import.
0201   bool isImportedAsNew(const Decl *ToDecl) const;
0202 
0203   /// Returns true if the given Decl is mapped (or created) during an import
0204   /// but there was an unrecoverable error (the AST node cannot be erased, it
0205   /// is marked with an Error object in this case).
0206   bool hasError(const Decl *ToDecl) const;
0207 
0208 private:
0209   void lazyInitImporterSharedSt(TranslationUnitDecl *ToTU);
0210   ASTImporter &getOrCreateASTImporter(ASTUnit *Unit);
0211   template <typename T>
0212   llvm::Expected<const T *> getCrossTUDefinitionImpl(const T *D,
0213                                                      StringRef CrossTUDir,
0214                                                      StringRef IndexName,
0215                                                      bool DisplayCTUProgress);
0216   template <typename T>
0217   const T *findDefInDeclContext(const DeclContext *DC,
0218                                 StringRef LookupName);
0219   template <typename T>
0220   llvm::Expected<const T *> importDefinitionImpl(const T *D, ASTUnit *Unit);
0221 
0222   using ImporterMapTy =
0223       llvm::DenseMap<TranslationUnitDecl *, std::unique_ptr<ASTImporter>>;
0224 
0225   ImporterMapTy ASTUnitImporterMap;
0226 
0227   ASTContext &Context;
0228   std::shared_ptr<ASTImporterSharedState> ImporterSharedSt;
0229 
0230   using LoadResultTy = llvm::Expected<std::unique_ptr<ASTUnit>>;
0231 
0232   /// Loads ASTUnits from AST-dumps or source-files.
0233   class ASTLoader {
0234   public:
0235     ASTLoader(CompilerInstance &CI, StringRef CTUDir,
0236               StringRef InvocationListFilePath);
0237 
0238     /// Load the ASTUnit by its identifier found in the index file. If the
0239     /// identifier is suffixed with '.ast' it is considered a dump. Otherwise
0240     /// it is treated as source-file, and on-demand parsed. Relative paths are
0241     /// prefixed with CTUDir.
0242     LoadResultTy load(StringRef Identifier);
0243 
0244     /// Lazily initialize the invocation list information, which is needed for
0245     /// on-demand parsing.
0246     llvm::Error lazyInitInvocationList();
0247 
0248   private:
0249     /// The style used for storage and lookup of filesystem paths.
0250     /// Defaults to posix.
0251     const llvm::sys::path::Style PathStyle = llvm::sys::path::Style::posix;
0252 
0253     /// Loads an AST from a pch-dump.
0254     LoadResultTy loadFromDump(StringRef Identifier);
0255     /// Loads an AST from a source-file.
0256     LoadResultTy loadFromSource(StringRef Identifier);
0257 
0258     CompilerInstance &CI;
0259     StringRef CTUDir;
0260     /// The path to the file containing the invocation list, which is in YAML
0261     /// format, and contains a mapping from source files to compiler invocations
0262     /// that produce the AST used for analysis.
0263     StringRef InvocationListFilePath;
0264     /// In case of on-demand parsing, the invocations for parsing the source
0265     /// files is stored.
0266     std::optional<InvocationListTy> InvocationList;
0267     index_error_code PreviousParsingResult = index_error_code::success;
0268   };
0269 
0270   /// Maintain number of AST loads and check for reaching the load limit.
0271   class ASTLoadGuard {
0272   public:
0273     ASTLoadGuard(unsigned Limit) : Limit(Limit) {}
0274 
0275     /// Indicates, whether a new load operation is permitted, it is within the
0276     /// threshold.
0277     operator bool() const { return Count < Limit; }
0278 
0279     /// Tell that a new AST was loaded successfully.
0280     void indicateLoadSuccess() { ++Count; }
0281 
0282   private:
0283     /// The number of ASTs actually imported.
0284     unsigned Count{0u};
0285     /// The limit (threshold) value for number of loaded ASTs.
0286     const unsigned Limit;
0287   };
0288 
0289   /// Storage and load of ASTUnits, cached access, and providing searchability
0290   /// are the concerns of ASTUnitStorage class.
0291   class ASTUnitStorage {
0292   public:
0293     ASTUnitStorage(CompilerInstance &CI);
0294     /// Loads an ASTUnit for a function.
0295     ///
0296     /// \param FunctionName USR name of the function.
0297     /// \param CrossTUDir Path to the directory used to store CTU related files.
0298     /// \param IndexName Name of the file inside \p CrossTUDir which maps
0299     /// function USR names to file paths. These files contain the corresponding
0300     /// AST-dumps.
0301     /// \param DisplayCTUProgress Display a message about loading new ASTs.
0302     ///
0303     /// \return An Expected instance which contains the ASTUnit pointer or the
0304     /// error occurred during the load.
0305     llvm::Expected<ASTUnit *> getASTUnitForFunction(StringRef FunctionName,
0306                                                     StringRef CrossTUDir,
0307                                                     StringRef IndexName,
0308                                                     bool DisplayCTUProgress);
0309     /// Identifies the path of the file which can be used to load the ASTUnit
0310     /// for a given function.
0311     ///
0312     /// \param FunctionName USR name of the function.
0313     /// \param CrossTUDir Path to the directory used to store CTU related files.
0314     /// \param IndexName Name of the file inside \p CrossTUDir which maps
0315     /// function USR names to file paths. These files contain the corresponding
0316     /// AST-dumps.
0317     ///
0318     /// \return An Expected instance containing the filepath.
0319     llvm::Expected<std::string> getFileForFunction(StringRef FunctionName,
0320                                                    StringRef CrossTUDir,
0321                                                    StringRef IndexName);
0322 
0323   private:
0324     llvm::Error ensureCTUIndexLoaded(StringRef CrossTUDir, StringRef IndexName);
0325     llvm::Expected<ASTUnit *> getASTUnitForFile(StringRef FileName,
0326                                                 bool DisplayCTUProgress);
0327 
0328     template <typename... T> using BaseMapTy = llvm::StringMap<T...>;
0329     using OwningMapTy = BaseMapTy<std::unique_ptr<clang::ASTUnit>>;
0330     using NonOwningMapTy = BaseMapTy<clang::ASTUnit *>;
0331 
0332     OwningMapTy FileASTUnitMap;
0333     NonOwningMapTy NameASTUnitMap;
0334 
0335     using IndexMapTy = BaseMapTy<std::string>;
0336     IndexMapTy NameFileMap;
0337 
0338     /// Loads the AST based on the identifier found in the index.
0339     ASTLoader Loader;
0340 
0341     /// Limit the number of loaded ASTs. It is used to limit the  memory usage
0342     /// of the CrossTranslationUnitContext. The ASTUnitStorage has the
0343     /// information whether the AST to load is actually loaded or returned from
0344     /// cache. This information is needed to maintain the counter.
0345     ASTLoadGuard LoadGuard;
0346   };
0347 
0348   ASTUnitStorage ASTStorage;
0349 };
0350 
0351 } // namespace cross_tu
0352 } // namespace clang
0353 
0354 #endif // LLVM_CLANG_CROSSTU_CROSSTRANSLATIONUNIT_H