Index: clang/include/clang/Index/CodegenNameGenerator.h =================================================================== --- clang/include/clang/Index/CodegenNameGenerator.h +++ clang/include/clang/Index/CodegenNameGenerator.h @@ -13,7 +13,6 @@ #ifndef LLVM_CLANG_INDEX_CODEGENNAMEGENERATOR_H #define LLVM_CLANG_INDEX_CODEGENNAMEGENERATOR_H -#include "clang/AST/Mangle.h" #include "clang/Basic/LLVM.h" #include #include @@ -43,7 +42,7 @@ private: struct Implementation; - std::unique_ptr Impl; + std::unique_ptr Impl; }; } // namespace index Index: clang/include/clang/Index/DeclOccurrenceCollector.h =================================================================== --- /dev/null +++ clang/include/clang/Index/DeclOccurrenceCollector.h @@ -0,0 +1,56 @@ +//===--- DeclOccurrenceCollector.h - Collecting data for index records --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_DECLOCCURENCECOLLECTOR_H +#define LLVM_CLANG_INDEX_DECLOCCURENCECOLLECTOR_H + +#include "clang/Index/IndexRecordWriter.h" +#include "clang/Index/IndexDataConsumer.h" +#include "clang/Index/IndexingContext.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include + +namespace clang { +namespace index { + +class DeclOccurrenceCollector : public IndexDataConsumer { + SourceManager &SM; + // This exists because there's cyclic dependency between IndexingContext and DeclOccurrenceCollector. + IndexingContext *IndexCtx = nullptr; + + llvm::DenseMap RecordByFile; + +public: + + explicit DeclOccurrenceCollector(SourceManager &SM) : SM(SM) { } + + void setIndexingContext(IndexingContext &IC) { IndexCtx = &IC; } + + bool handleMacroOccurence(const IdentifierInfo *Name, + const MacroInfo *MI, SymbolRoleSet Roles, + SourceLocation Loc) override { return true; } + bool handleModuleOccurence(const ImportDecl *ImportD, + const Module *Mod, + SymbolRoleSet Roles, SourceLocation Loc) override { return true; } + + const llvm::DenseMap& getRecordByFile() const { return RecordByFile; } + + bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles, + ArrayRef Relations, + SourceLocation Loc, ASTNodeInfo ASTNode) override; + + void initialize(ASTContext&) override { } + void setPreprocessor(std::shared_ptr) override { } + void finish() override { } +}; + +} // namespace index +} // namespace clang + +#endif Index: clang/include/clang/Index/EmitIndexAction.h =================================================================== --- /dev/null +++ clang/include/clang/Index/EmitIndexAction.h @@ -0,0 +1,94 @@ +//===--- EmitIndexAction.h - Index emitting action --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_EMITINDEXACTION_H +#define LLVM_CLANG_INDEX_EMITINDEXACTION_H + +#include "clang/Index/IndexAction.h" +#include "clang/Index/IndexDataConsumer.h" +#include "clang/Index/DeclOccurrenceCollector.h" +#include "clang/Index/IndexingContext.h" +#include "clang/Index/IndexRecordWriter.h" +#include "clang/Index/IndexUnitWriter.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "llvm/ADT/StringRef.h" +#include + +namespace clang { +namespace index { + +class SourceFilesDependencyCollector : public DependencyCollector { + const CompilerInstance &CI; + IndexingContext &IndexCtx; + RecordingOptions RecordOpts; + +public: + IndexUnitWriter UnitWriter; + + SourceFilesDependencyCollector( + const CompilerInstance &CI, + IndexingContext &indexCtx, + RecordingOptions recordOpts + ); + + virtual void attachToPreprocessor(Preprocessor &PP) override; +private: + bool sawDependency(StringRef Filename, bool FromModule, bool IsSystem, + bool IsModuleFile, bool IsMissing) override; + bool isInSysroot(StringRef Filename); +}; + +// FIXME: +// This isn't nice - just a glue. +// The reasons for this to exist are: +// - We need access to CompilerInstance to create collectors which we get only in CreateASTConsumer method, not in action constructor. +// - createIndexRecordingASTConsumer returns unique_ptr but we need to preserve some data until EndSourceFileAction. +struct ActionContext { + const CompilerInstance& CI; + DeclOccurrenceCollector DeclsDataCollector; + IndexingContext Ctx; + SourceFilesDependencyCollector DepCollector; + RecordingOptions RecordOpts; + IndexingOptions IndexOpts; + + ActionContext(const IndexingOptions& IndexOpts, const CompilerInstance &CI, const RecordingOptions& RecordOpts); + + void emitCollectedData(); +}; + +/// Generates and serializes index data to disk. +class EmitIndexAction : public IndexAction { + RecordingOptions RecordOpts; + IndexingOptions IndexOpts; + std::shared_ptr Context = nullptr; + +public: + EmitIndexAction(const IndexingOptions& IndexOpts, + const RecordingOptions& RecordOpts); + + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + StringRef) override; + + void EndSourceFileAction() override; +}; + +/// Checks if the unit file exists for \p Mod and emits index data in case it doesn't. +/// +/// \returns true if the index data were generated, false otherwise. +bool emitIndexDataForModule(const Module *Mod, const CompilerInstance &CI); + +/// Emits index data for \p Mod. +void emitIndexDataForModuleFile(serialization::ModuleFile &Mod, + const CompilerInstance &CI, const IndexingOptions& IndexOpts, + const RecordingOptions& RecordOpts); + +} // namespace index +} // namespace clang + +#endif Index: clang/include/clang/Index/GenerateIndexAction.h =================================================================== --- /dev/null +++ clang/include/clang/Index/GenerateIndexAction.h @@ -0,0 +1,73 @@ +//===--- GenerateIndexAction.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_INDEXINGACTION_H +#define LLVM_CLANG_INDEX_INDEXINGACTION_H + +#include "clang/Index/IndexAction.h" +#include "clang/Index/IndexDataConsumer.h" +#include "clang/Index/IndexingContext.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "llvm/ADT/StringRef.h" +#include + +namespace clang { + class ASTContext; + class ASTReader; + class ASTUnit; + class CompilerInstance; + class Decl; + class FrontendAction; + +namespace serialization { + class ModuleFile; +} + +namespace index { + class IndexDataConsumer; + class IndexUnitWriter; + +/// Recursively indexes all decls in the \p Unit and feeds them to \p DataConsumer. +void indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer, + const IndexingOptions& Opts); + +/// Recursively indexes \p Decls and feeds them to \p DataConsumer. +void indexTopLevelDecls(ASTContext &Ctx, Preprocessor &PP, + ArrayRef Decls, + IndexDataConsumer &DataConsumer, const IndexingOptions& Opts); + +/// Creates a PPCallbacks that indexes macros and feeds them to \p Consumer. +/// The caller is responsible for calling `Consumer.setPreprocessor()`. +std::unique_ptr indexMacrosCallback(IndexDataConsumer &Consumer, + const IndexingOptions& Opts); + +/// Recursively indexes all top-level decls in the \p Mod and feeds them to \p DataConsumer. +void indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader, + IndexDataConsumer &DataConsumer, const IndexingOptions& Opts); + +/// Generates index and uses IndexDataConsumer to consume it. +class GenerateIndexAction : public IndexAction { + std::shared_ptr DataConsumer; + std::shared_ptr IndexCtx; + +public: + GenerateIndexAction(std::shared_ptr DataConsumer, + const IndexingOptions& Opts + ); + + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + + void EndSourceFileAction() override; +}; + +} // namespace index +} // namespace clang + +#endif Index: clang/include/clang/Index/IndexAction.h =================================================================== --- /dev/null +++ clang/include/clang/Index/IndexAction.h @@ -0,0 +1,49 @@ +//===--- IndexAction.h - Interface for index actions ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_INDEXACTION_H +#define LLVM_CLANG_INDEX_INDEXACTION_H + +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "llvm/ADT/StringRef.h" +#include + +namespace clang { +namespace index { + +class IndexActionWrapper; + +/// This is primarily a hack - poking hole through FrontendAction encapsulation in order to access protected methods from IndexActionWrapper. FIXME? +/// Auxiliary purpose is type distinction for two different actions in IndexActionWrapper in order to quarantee their methods are called in correct order. +class IndexAction : public ASTFrontendAction { + friend class IndexActionWrapper; +}; + +/// Combines implementation of WrappedActionParam and IndexingActionParam. +/// AST consumer produced by CreateASTConsumer method first invokes consumer created by WrappedActionParam and then consumer created by IndexingActionParam. +/// EndSourceFileAction invokes first implementation of the same method in WrappedActionParam and then implementation in IndexingActionParam. +class IndexActionWrapper : public WrapperFrontendAction { + std::unique_ptr IndexingAction; + +public: + IndexActionWrapper( + std::unique_ptr IndexingActionParam, + std::unique_ptr WrappedActionParam + ); + + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + + void EndSourceFileAction() override; +}; + +} // namespace index +} // namespace clang + +#endif Index: clang/include/clang/Index/IndexDataConsumer.h =================================================================== --- clang/include/clang/Index/IndexDataConsumer.h +++ clang/include/clang/Index/IndexDataConsumer.h @@ -32,21 +32,21 @@ const DeclContext *ContainerDC; }; - virtual ~IndexDataConsumer() {} + virtual ~IndexDataConsumer() = default; - virtual void initialize(ASTContext &Ctx) {} + virtual void initialize(ASTContext &Ctx) = 0; - virtual void setPreprocessor(std::shared_ptr PP) {} + virtual void setPreprocessor(std::shared_ptr PP) = 0; /// \returns true to continue indexing, or false to abort. virtual bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles, ArrayRef Relations, - SourceLocation Loc, ASTNodeInfo ASTNode); + SourceLocation Loc, ASTNodeInfo ASTNode) = 0; /// \returns true to continue indexing, or false to abort. virtual bool handleMacroOccurence(const IdentifierInfo *Name, const MacroInfo *MI, SymbolRoleSet Roles, - SourceLocation Loc); + SourceLocation Loc) = 0; /// \returns true to continue indexing, or false to abort. /// @@ -55,9 +55,9 @@ /// 'reference' role, and a call for 'SubMod' with the 'declaration' role. virtual bool handleModuleOccurence(const ImportDecl *ImportD, const Module *Mod, - SymbolRoleSet Roles, SourceLocation Loc); + SymbolRoleSet Roles, SourceLocation Loc) = 0; - virtual void finish() {} + virtual void finish() = 0; }; } // namespace index Index: clang/include/clang/Index/IndexDataFormat.h =================================================================== --- /dev/null +++ clang/include/clang/Index/IndexDataFormat.h @@ -0,0 +1,112 @@ +//===--- IndexDataStoreUtils.h - Functions/constants for the data store ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_INDEX_INDEXDATAFORMAT_H +#define LLVM_CLANG_LIB_INDEX_INDEXDATAFORMAT_H + +#include "llvm/Bitstream/BitCodes.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace index { +namespace store { + +/// \returns version of index format +unsigned getIndexFormatVersion(); + +/// Index is organized on disk like this: +/// (root of index dir) +/// / +/// / +/// /AA +/// /(records) +/// /AB +/// /(records) +/// /AC +/// /(records) +/// ... +/// / +/// /(units) + +/// \returns name of directory where index data lives inside the root directory. +const char* getIndexDir(); + +/// \returns name of directory where unit data lives inside the index directory. +const char* getIndexUnitSubdir(); + +/// \returns name of directory where record data lives inside the index directory. +const char* getIndexRecordSubdir(); + +/// Appends unit subdirectory to \p Buffer without erasing it. +void appendUnitSubDir(llvm::SmallVectorImpl &Buffer); + +/// Appends record subdirectory to \p Buffer without erasing it. +void appendRecordSubDir(llvm::SmallVectorImpl &Buffer); + +/// This is currently a placeholder - just appends \p UnitName to \p Buffer. +void appendUnitBucketDir(llvm::StringRef UnitName, + llvm::SmallVectorImpl &Buffer); + +/// We're bucketing record files according to the last two characters in their names in order to keep number of files in a single directory reasonable. +/// Appends bucket subdirectory and delimiter. +void appendRecordBucketDir(llvm::StringRef RecordName, + llvm::SmallVectorImpl &Buffer); + +/// Appends \p RecordName to \p Buffer. +void appendRecordFilename(llvm::StringRef RecordName, + llvm::SmallVectorImpl &Buffer); + +enum RecordBitRecord { + REC_VERSION = 0, + REC_DECLINFO = 1, + REC_DECLOFFSETS = 2, + REC_DECLOCCURRENCE = 3, +}; + +enum RecordBitBlock { + REC_VERSION_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, + REC_DECLS_BLOCK_ID, + REC_DECLOFFSETS_BLOCK_ID, + REC_DECLOCCURRENCES_BLOCK_ID, +}; + +enum UnitBitRecord { + UNIT_VERSION = 0, + UNIT_INFO = 1, + UNIT_DEPENDENCY = 2, + UNIT_INCLUDE = 3, + UNIT_PATH = 4, + UNIT_PATH_BUFFER = 5, + UNIT_MODULE = 6, + UNIT_MODULE_BUFFER = 7, +}; + +enum UnitBitBlock { + UNIT_VERSION_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, + UNIT_INFO_BLOCK_ID, + UNIT_DEPENDENCIES_BLOCK_ID, + UNIT_INCLUDES_BLOCK_ID, + UNIT_PATHS_BLOCK_ID, + UNIT_MODULES_BLOCK_ID, +}; + +enum UnitDependencyKind { + UNIT_DEPEND_KIND_FILE = 0, + UNIT_DEPEND_KIND_RECORD = 1, + UNIT_DEPEND_KIND_UNIT = 2, +}; +static const unsigned UnitDependencyKindBitNum = 2; +static const unsigned UnitFilePathPrefixKindBitNum = 2; + +} // end namespace store +} // end namespace index +} // end namespace clang + +#endif Index: clang/include/clang/Index/IndexDataStore.h =================================================================== --- /dev/null +++ clang/include/clang/Index/IndexDataStore.h @@ -0,0 +1,75 @@ +//===--- IndexDataStore.h - Index data store info -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_INDEXDATASTORE_H +#define LLVM_CLANG_INDEX_INDEXDATASTORE_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Chrono.h" +#include +#include +#include + +namespace clang { +namespace index { + +class IndexDataStore { +public: + ~IndexDataStore(); + + static std::unique_ptr + create(StringRef IndexStorePath, std::string &Error); + + StringRef getFilePath() const; + bool foreachUnitName(bool sorted, + llvm::function_ref receiver); + + static unsigned getFormatVersion(); + + enum class UnitEventKind { + Added, + Removed, + Modified, + /// The directory got deleted. No more events will follow. + DirectoryDeleted, + }; + struct UnitEvent { + UnitEventKind Kind; + StringRef UnitName; + llvm::sys::TimePoint<> ModTime; + }; + struct UnitEventNotification { + bool IsInitial; + ArrayRef Events; + }; + typedef std::function UnitEventHandler; + + void setUnitEventHandler(UnitEventHandler Handler); + /// \returns true if an error occurred. + bool startEventListening(bool waitInitialSync, std::string &Error); + void stopEventListening(); + + void discardUnit(StringRef UnitName); + void discardRecord(StringRef RecordName); + + void purgeStaleData(); + +private: + IndexDataStore(void *Impl) : Impl(Impl) {} + + void *Impl; // An IndexDataStoreImpl. +}; + +} // namespace index +} // namespace clang + +#endif Index: clang/include/clang/Index/IndexOptions.h =================================================================== --- /dev/null +++ clang/include/clang/Index/IndexOptions.h @@ -0,0 +1,71 @@ +//===--- IndexOptions.h - Frontend index action -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_INDEXOPITONS_H +#define LLVM_CLANG_INDEX_INDEXOPITONS_H + +#include "clang/Frontend/FrontendOptions.h" +#include +#include + +namespace clang { +namespace index { + +struct IndexingOptions { + enum class SystemSymbolFilterKind { + None, + DeclarationsOnly, + All, + }; + + SystemSymbolFilterKind SystemSymbolFilter + = SystemSymbolFilterKind::DeclarationsOnly; + bool IndexFunctionLocals = false; + bool IndexImplicitInstantiation = false; + // Whether to index macro definitions in the Preprocesor when preprocessor + // callback is not available (e.g. after parsing has finished). Note that + // macro references are not available in Proprocessor. + bool IndexMacrosInPreprocessor = false; + // Has no effect if IndexFunctionLocals are false. + bool IndexParametersInDeclarations = false; + bool IndexTemplateParameters = false; +}; + +struct RecordingOptions { + enum class IncludesRecordingKind { + None, + UserOnly, // only record includes inside non-system files. + All, + }; + + const std::string RootDir; + // Caching the full paths. + const std::string IndexDir; + const std::string UnitDir; + const std::string RecordDir; + + const bool RecordSymbolCodeGenName; + const bool RecordSystemDependencies; + const IncludesRecordingKind RecordIncludes; + + RecordingOptions( + const StringRef RootDir, + const bool RecordSymbolCodeGenName = false, + const bool RecordSystemDependencies = true, + const IncludesRecordingKind RecordIncludes = IncludesRecordingKind::UserOnly + ); +}; + +IndexingOptions parseIndexGenerationOptions(const FrontendOptions &FEOpts); + +RecordingOptions parseIndexEmittingOptions(const FrontendOptions &FEOpts); + +} // namespace index +} // namespace clang + +#endif Index: clang/include/clang/Index/IndexRecordWriter.h =================================================================== --- /dev/null +++ clang/include/clang/Index/IndexRecordWriter.h @@ -0,0 +1,74 @@ +//===--- IndexRecordWriter.h - Index data per file ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_INDEX_FILEINDEXRECORD_H +#define LLVM_CLANG_LIB_INDEX_FILEINDEXRECORD_H + +#include "clang/AST/DeclBase.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Index/CodegenNameGenerator.h" +#include "clang/Index/DeclOccurrence.h" +#include "clang/Index/IndexOptions.h" +#include "clang/Index/IndexSymbol.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Bitstream/BitstreamWriter.h" +#include +#include + +namespace clang { +namespace index { + +struct DeclInfo { + const Decl* D; + SymbolRoleSet Roles; + SymbolRoleSet RelatedRoles; +}; + +/// Stores the declaration occurrences seen in a particular source or header +/// file of a translation unit. +class IndexRecordWriter { +private: + bool IsSystem; + + llvm::DenseMap IndexForDecl; + std::vector DeclsNG; + std::multimap> OccurrencesNG; + +public: + IndexRecordWriter(bool IsSystem) : IsSystem(IsSystem) {} + + bool isSystem() const { return IsSystem; } + + /// Adds an occurrence of the canonical declaration \c D at the supplied + /// \c Offset + /// + /// \param Roles the roles the occurrence fulfills in this position. + /// \param Offset the offset in the file of this occurrence. + /// \param D the canonical declaration this is an occurrence of. + /// \param Relations the set of symbols related to this occurrence. + void addDeclOccurence(SymbolRoleSet Roles, FileID FID, unsigned Offset, const Decl *D, + ArrayRef Relations); + + /// Writes \p Record to \p Stream. + // TODO Rename to getBitcodeReprentation and unify interface with IndexUnitWriter::writeToDisk. + void serialize(llvm::BitstreamWriter &Stream, const clang::PrintingPolicy& Policy, + std::shared_ptr CGNameGen) const; + + bool isEmpty() const { return DeclsNG.empty(); } + + // TODO Mention handling of empty files. + /// \returns Filename of the recordfile. + llvm::Optional writeToDisk(StringRef SourceFileName, const RecordingOptions& RecOpts, const PrintingPolicy& Policy, std::shared_ptr CGNameGen, DiagnosticsEngine &Diag) const; +}; + +} // end namespace index +} // end namespace clang + +#endif // LLVM_CLANG_LIB_INDEX_FILEINDEXRECORD_H Index: clang/include/clang/Index/IndexUnitWriter.h =================================================================== --- /dev/null +++ clang/include/clang/Index/IndexUnitWriter.h @@ -0,0 +1,172 @@ +//===--- IndexUnitWriter.h - Index unit serialization ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_INDEXUNITWRITER_H +#define LLVM_CLANG_INDEX_INDEXUNITWRITER_H + +#include "clang/Basic/LLVM.h" +#include "clang/Index/IndexOptions.h" +#include "clang/Index/PathStorage.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Allocator.h" +#include +#include +#include + +namespace llvm { + class BitstreamWriter; +} + +namespace clang { + class CompilerInstance; + class FileEntry; + class FileManager; + class Module; + +namespace index { + +namespace writer { +/// An opaque pointer to a module used by the IndexUnitWriter to associate +/// record and file dependencies with a module, and as a token for getting +/// information about the module from the caller. +typedef const void *OpaqueModule; + +/// Module info suitable for serialization. +/// +/// This is used for top-level modules and sub-modules. +struct ModuleInfo { + /// Full, dot-separate, module name. + StringRef Name; +}; + +typedef llvm::function_ref &Scratch)> + ModuleInfoWriterCallback; +} // end namespace writer + +struct ModuleIndexData { + const std::string Name; + const bool IsSystem; + // We clearly don't expect system sources being indexed/built. +}; + +class IndexUnitWriter { +private: + const RecordingOptions RecOpts; + + // index unit metadata + const std::string ProviderIdentifier; + const std::string ProviderVersion; + const std::string OutputFile; + const std::string AbsPathToOutputFile; + const FileEntry *MainFile; + + // Absence of value means this is not a module. + const llvm::Optional ModuleData; + + const bool IsDebugCompilation; + const std::string TargetTriple; + const std::string WorkDir; + // FIXME + // IIUC we're serializing this as a source of truth of what is considered a system part of directory tree but we should probably be using values of all of -isysroot, -isystem and -F options. + const std::string SysrootPath; + + // Actual index unit data + + mutable PathStorage PathStore; + + // Codebase level dependencies + + // Modules + SmallString<512> ModuleNamesBuf; + std::vector> Modules; + // Maps module to its one-based index in the Modules container. + llvm::DenseMap ModToIdx; + + llvm::DenseMap> SourceFiles; + // Source files that has a corresponding IndexRecord aren't written into index. + llvm::DenseSet SourceFileHasARecord; + + std::vector> IncludedFiles; + + // Index level dependencies + + // Index units that this unit depends on + std::vector, std::array>> IndexUnitDependencies; + llvm::DenseSet ASTFilesOfSeenIndexUnits; + + std::vector>> IndexRecordDependencies; + + + + std::function &Scratch)> GetInfoForModuleFn; + + +public: + /// \param MainFile the main file for a compiled source file. This should be + /// null for PCH and module units. + /// \param IsSystem true for system module units, false otherwise. + IndexUnitWriter(FileManager &FileMgr, + const RecordingOptions& RecOpts, + StringRef ProviderIdentifier, StringRef ProviderVersion, + StringRef OutputFile, + StringRef AbsPathToOutputFile, + const FileEntry *MainFile, + const llvm::Optional& ModuleData, + bool IsDebugCompilation, + StringRef TargetTriple, + StringRef WorkDir, + StringRef SysrootPath, + writer::ModuleInfoWriterCallback GetInfoForModule); + + unsigned addModule(writer::OpaqueModule Mod); + void addSourceFile(const FileEntry *File, bool IsSystem, + writer::OpaqueModule Mod); + void addIndexRecord(StringRef RecordFile, const FileEntry *SourceFile, bool IsSystem,writer::OpaqueModule Mod); + + void addIndexUnit(const FileEntry *File, + StringRef AbsolutePath, + bool IsSystem, + writer::OpaqueModule Mod, bool withoutUnitName = false); + void addIncludedFile(const FileEntry *Source, unsigned Line, const FileEntry *Target); + + bool writeToDisk(std::string &Error) const; + +private: + void writeUnitInfo(llvm::BitstreamWriter &Stream) const; + void writeDependencies(llvm::BitstreamWriter &Stream) const; + void writeIncludes(llvm::BitstreamWriter &Stream) const; + void writePaths(llvm::BitstreamWriter &Stream) const; + void writeModules(llvm::BitstreamWriter &Stream) const; + + SmallString<512> getBitcodeReprentation(std::string &Error) const; +}; + +IndexUnitWriter makeIndexUnitWriter( + const CompilerInstance &CI, + const RecordingOptions& RecordOpts, + StringRef OutputFile, + const FileEntry *MainFile, + Module *UnitModule +); + +bool initIndexDirectory(const RecordingOptions& RecordingOpts, std::string &Error); + +void getUnitNameForAbsoluteOutputFile(StringRef FilePath, SmallVectorImpl &Str); + +// \returns llvm::None in case module's IndexUnit couldn't be stat()-ed +llvm::Optional doesIndexUnitForModuleExist(StringRef ModuleFilePath, const FileManager& FileMgr, const RecordingOptions &RecOpts +); + +} // end namespace index +} // end namespace clang + +#endif Index: clang/include/clang/Index/IndexingContext.h =================================================================== --- /dev/null +++ clang/include/clang/Index/IndexingContext.h @@ -0,0 +1,152 @@ +//===- IndexingContext.h - Indexing context data ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_INDEX_INDEXINGCONTEXT_H +#define LLVM_CLANG_LIB_INDEX_INDEXINGCONTEXT_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Index/IndexSymbol.h" +#include "clang/Index/IndexOptions.h" +#include "clang/Lex/MacroInfo.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + class ASTContext; + class Decl; + class DeclGroupRef; + class ImportDecl; + class TagDecl; + class TypeSourceInfo; + class NamedDecl; + class ObjCMethodDecl; + class DeclContext; + class NestedNameSpecifierLoc; + class Stmt; + class Expr; + class TypeLoc; + class DirectoryEntry; + +namespace index { + class IndexDataConsumer; + +class IndexingContext { + IndexingOptions IndexOpts; + IndexDataConsumer &DataConsumer; + ASTContext *Ctx = nullptr; + std::string SysrootPath; + + // Records whether a directory entry is system or not. + llvm::DenseMap DirEntries; + // Keeps track of the last check for whether a FileID is system or + // not. This is used to speed up isSystemFile() call. + std::pair LastFileCheck; + +public: + IndexingContext(IndexingOptions IndexOpts, IndexDataConsumer &DataConsumer) + : IndexOpts(IndexOpts), DataConsumer(DataConsumer) {} + + const IndexingOptions &getIndexOpts() const { return IndexOpts; } + IndexDataConsumer &getDataConsumer() { return DataConsumer; } + + void setASTContext(ASTContext &ctx) { Ctx = &ctx; } + void setSysrootPath(StringRef path); + StringRef getSysrootPath() const { return SysrootPath; } + + bool isSystemFile(FileID FID); + + bool shouldIndex(const Decl *D); + + const LangOptions &getLangOpts() const; + + bool shouldSuppressRefs() const { + return false; + } + + bool shouldIndexFunctionLocalSymbols() const; + + bool shouldIndexImplicitInstantiation() const; + + bool shouldIndexParametersInDeclarations() const; + + bool shouldIndexTemplateParameters() const; + + static bool isTemplateImplicitInstantiation(const Decl *D); + + bool handleDecl(const Decl *D, SymbolRoleSet Roles = SymbolRoleSet(), + ArrayRef Relations = None); + + bool handleDecl(const Decl *D, SourceLocation Loc, + SymbolRoleSet Roles = SymbolRoleSet(), + ArrayRef Relations = None, + const DeclContext *DC = nullptr); + + bool handleReference(const NamedDecl *D, SourceLocation Loc, + const NamedDecl *Parent, + const DeclContext *DC, + SymbolRoleSet Roles = SymbolRoleSet(), + ArrayRef Relations = None, + const Expr *RefE = nullptr, + const Decl *RefD = nullptr); + + void handleMacroDefined(const IdentifierInfo &Name, SourceLocation Loc, + const MacroInfo &MI); + + void handleMacroUndefined(const IdentifierInfo &Name, SourceLocation Loc, + const MacroInfo &MI); + + void handleMacroReference(const IdentifierInfo &Name, SourceLocation Loc, + const MacroInfo &MD); + + bool importedModule(const ImportDecl *ImportD); + + bool indexDecl(const Decl *D); + + void indexTagDecl(const TagDecl *D, + ArrayRef Relations = None); + + void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent, + const DeclContext *DC = nullptr, + bool isBase = false, + bool isIBType = false); + + void indexTypeLoc(TypeLoc TL, const NamedDecl *Parent, + const DeclContext *DC = nullptr, + bool isBase = false, + bool isIBType = false); + + void indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, + const NamedDecl *Parent, + const DeclContext *DC = nullptr); + + bool indexDeclContext(const DeclContext *DC); + + void indexBody(const Stmt *S, const NamedDecl *Parent, + const DeclContext *DC = nullptr); + + bool indexTopLevelDecl(const Decl *D); + bool indexDeclGroupRef(DeclGroupRef DG); + +private: + bool shouldIgnoreIfImplicit(const Decl *D); + + bool handleDeclOccurrence(const Decl *D, SourceLocation Loc, + bool IsRef, const Decl *Parent, + SymbolRoleSet Roles, + ArrayRef Relations, + const Expr *RefE, + const Decl *RefD, + const DeclContext *ContainerDC); +}; + +} // end namespace index +} // end namespace clang + +#endif Index: clang/include/clang/Index/PathStorage.h =================================================================== --- /dev/null +++ clang/include/clang/Index/PathStorage.h @@ -0,0 +1,67 @@ +#ifndef MESS +#define MESS + +#include "clang/Basic/FileManager.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallString.h" + +#include +#include + +enum UnitFilePathPrefixKind { + UNIT_PATH_PREFIX_NONE = 0, + UNIT_PATH_PREFIX_WORKDIR = 1, + UNIT_PATH_PREFIX_SYSROOT = 2, +}; + +struct BitPathComponent { + size_t Offset = 0; + size_t Size = 0; + BitPathComponent(size_t Offset, size_t Size) : Offset(Offset), Size(Size) {} + BitPathComponent() = default; +}; + +struct DirBitPath { + UnitFilePathPrefixKind PrefixKind; + BitPathComponent Dir; + + DirBitPath(UnitFilePathPrefixKind Kind, + BitPathComponent Dir); + DirBitPath(); +}; + +struct FileBitPath : DirBitPath { + BitPathComponent Filename; + FileBitPath(UnitFilePathPrefixKind Kind, BitPathComponent Dir, + BitPathComponent Filename) : DirBitPath(Kind, Dir), Filename(Filename) {} + FileBitPath() = default; +}; + +class PathStorage { + std::string WorkDir; + std::string SysrootPath; + llvm::SmallString<512> PathsBuf; + llvm::StringMap Dirs; + std::vector FileBitPaths; + llvm::DenseMap FileToIndex; + +public: + PathStorage(llvm::StringRef workDir, llvm::StringRef sysrootPath); + + // used in IndexUnitWriter 1 + llvm::StringRef getPathsBuffer() const { return PathsBuf.str(); } + + // used in IndexUnitWriter 1 + llvm::ArrayRef getBitPaths() const { return FileBitPaths; } + + int getPathIndex(const clang::FileEntry *FE); + + size_t getPathOffset(llvm::StringRef Path); + +private: + DirBitPath getDirBitPath(llvm::StringRef dirStr); +}; + +#endif \ No newline at end of file Index: clang/include/indexstore/Conversions.h =================================================================== --- /dev/null +++ clang/include/indexstore/Conversions.h @@ -0,0 +1,453 @@ +//===--- IndexDataStoreSymbolUtils.h - Utilities for indexstore symbols ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_INDEXDATASTORESYMBOLUTILS_H +#define LLVM_CLANG_INDEX_INDEXDATASTORESYMBOLUTILS_H + +#include "indexstore/indexstore.h" +#include "clang/Index/IndexSymbol.h" + +namespace clang { +namespace index { + +inline SymbolKind getSymbolKind(indexstore_symbol_kind_t K) { + switch ((uint64_t)K) { + default: + case INDEXSTORE_SYMBOL_KIND_UNKNOWN: + return SymbolKind::Unknown; + case INDEXSTORE_SYMBOL_KIND_MODULE: + return SymbolKind::Module; + case INDEXSTORE_SYMBOL_KIND_NAMESPACE: + return SymbolKind::Namespace; + case INDEXSTORE_SYMBOL_KIND_NAMESPACEALIAS: + return SymbolKind::NamespaceAlias; + case INDEXSTORE_SYMBOL_KIND_MACRO: + return SymbolKind::Macro; + case INDEXSTORE_SYMBOL_KIND_ENUM: + return SymbolKind::Enum; + case INDEXSTORE_SYMBOL_KIND_STRUCT: + return SymbolKind::Struct; + case INDEXSTORE_SYMBOL_KIND_CLASS: + return SymbolKind::Class; + case INDEXSTORE_SYMBOL_KIND_PROTOCOL: + return SymbolKind::Protocol; + case INDEXSTORE_SYMBOL_KIND_EXTENSION: + return SymbolKind::Extension; + case INDEXSTORE_SYMBOL_KIND_UNION: + return SymbolKind::Union; + case INDEXSTORE_SYMBOL_KIND_TYPEALIAS: + return SymbolKind::TypeAlias; + case INDEXSTORE_SYMBOL_KIND_FUNCTION: + return SymbolKind::Function; + case INDEXSTORE_SYMBOL_KIND_VARIABLE: + return SymbolKind::Variable; + case INDEXSTORE_SYMBOL_KIND_FIELD: + return SymbolKind::Field; + case INDEXSTORE_SYMBOL_KIND_ENUMCONSTANT: + return SymbolKind::EnumConstant; + case INDEXSTORE_SYMBOL_KIND_INSTANCEMETHOD: + return SymbolKind::InstanceMethod; + case INDEXSTORE_SYMBOL_KIND_CLASSMETHOD: + return SymbolKind::ClassMethod; + case INDEXSTORE_SYMBOL_KIND_STATICMETHOD: + return SymbolKind::StaticMethod; + case INDEXSTORE_SYMBOL_KIND_INSTANCEPROPERTY: + return SymbolKind::InstanceProperty; + case INDEXSTORE_SYMBOL_KIND_CLASSPROPERTY: + return SymbolKind::ClassProperty; + case INDEXSTORE_SYMBOL_KIND_STATICPROPERTY: + return SymbolKind::StaticProperty; + case INDEXSTORE_SYMBOL_KIND_CONSTRUCTOR: + return SymbolKind::Constructor; + case INDEXSTORE_SYMBOL_KIND_DESTRUCTOR: + return SymbolKind::Destructor; + case INDEXSTORE_SYMBOL_KIND_CONVERSIONFUNCTION: + return SymbolKind::ConversionFunction; + case INDEXSTORE_SYMBOL_KIND_PARAMETER: + return SymbolKind::Parameter; + case INDEXSTORE_SYMBOL_KIND_USING: + return SymbolKind::Using; + case INDEXSTORE_SYMBOL_KIND_COMMENTTAG: + return SymbolKind::CommentTag; + } +} + +inline SymbolSubKind getSymbolSubKind(indexstore_symbol_subkind_t K) { + switch ((uint64_t)K) { + default: + case INDEXSTORE_SYMBOL_SUBKIND_NONE: + return SymbolSubKind::None; + case INDEXSTORE_SYMBOL_SUBKIND_CXXCOPYCONSTRUCTOR: + return SymbolSubKind::CXXCopyConstructor; + case INDEXSTORE_SYMBOL_SUBKIND_CXXMOVECONSTRUCTOR: + return SymbolSubKind::CXXMoveConstructor; + case INDEXSTORE_SYMBOL_SUBKIND_ACCESSORGETTER: + return SymbolSubKind::AccessorGetter; + case INDEXSTORE_SYMBOL_SUBKIND_ACCESSORSETTER: + return SymbolSubKind::AccessorSetter; + case INDEXSTORE_SYMBOL_SUBKIND_USINGTYPENAME: + return SymbolSubKind::UsingTypename; + case INDEXSTORE_SYMBOL_SUBKIND_USINGVALUE: + return SymbolSubKind::UsingValue; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORWILLSET: + return SymbolSubKind::SwiftAccessorWillSet; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORDIDSET: + return SymbolSubKind::SwiftAccessorDidSet; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORADDRESSOR: + return SymbolSubKind::SwiftAccessorAddressor; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORMUTABLEADDRESSOR: + return SymbolSubKind::SwiftAccessorMutableAddressor; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORREAD: + return SymbolSubKind::SwiftAccessorRead; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORMODIFY: + return SymbolSubKind::SwiftAccessorModify; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFSTRUCT: + return SymbolSubKind::SwiftExtensionOfStruct; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFCLASS: + return SymbolSubKind::SwiftExtensionOfClass; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFENUM: + return SymbolSubKind::SwiftExtensionOfEnum; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFPROTOCOL: + return SymbolSubKind::SwiftExtensionOfProtocol; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTPREFIXOPERATOR: + return SymbolSubKind::SwiftPrefixOperator; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTPOSTFIXOPERATOR: + return SymbolSubKind::SwiftPostfixOperator; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTINFIXOPERATOR: + return SymbolSubKind::SwiftInfixOperator; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTSUBSCRIPT: + return SymbolSubKind::SwiftSubscript; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTASSOCIATEDTYPE: + return SymbolSubKind::SwiftAssociatedType; + case INDEXSTORE_SYMBOL_SUBKIND_SWIFTGENERICTYPEPARAM: + return SymbolSubKind::SwiftGenericTypeParam; + } +} + +inline SymbolLanguage getSymbolLanguage(indexstore_symbol_language_t L) { + switch ((uint64_t)L) { + default: // FIXME: add an unknown language? + case INDEXSTORE_SYMBOL_LANG_C: + return SymbolLanguage::C; + case INDEXSTORE_SYMBOL_LANG_OBJC: + return SymbolLanguage::ObjC; + case INDEXSTORE_SYMBOL_LANG_CXX: + return SymbolLanguage::CXX; + case INDEXSTORE_SYMBOL_LANG_SWIFT: + return SymbolLanguage::Swift; + } +} + +inline SymbolPropertySet getSymbolProperties(uint64_t Props) { + SymbolPropertySet SymbolProperties = 0; + if (Props & INDEXSTORE_SYMBOL_PROPERTY_GENERIC) + SymbolProperties |= (SymbolPropertySet)SymbolProperty::Generic; + if (Props & INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_PARTIAL_SPECIALIZATION) + SymbolProperties |= (SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization; + if (Props & INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_SPECIALIZATION) + SymbolProperties |= (SymbolPropertySet)SymbolProperty::TemplateSpecialization; + if (Props & INDEXSTORE_SYMBOL_PROPERTY_UNITTEST) + SymbolProperties |= (SymbolPropertySet)SymbolProperty::UnitTest; + if (Props & INDEXSTORE_SYMBOL_PROPERTY_IBANNOTATED) + SymbolProperties |= (SymbolPropertySet)SymbolProperty::IBAnnotated; + if (Props & INDEXSTORE_SYMBOL_PROPERTY_IBOUTLETCOLLECTION) + SymbolProperties |= (SymbolPropertySet)SymbolProperty::IBOutletCollection; + if (Props & INDEXSTORE_SYMBOL_PROPERTY_GKINSPECTABLE) + SymbolProperties |= (SymbolPropertySet)SymbolProperty::GKInspectable; + if (Props & INDEXSTORE_SYMBOL_PROPERTY_LOCAL) + SymbolProperties |= (SymbolPropertySet)SymbolProperty::Local; + if (Props & INDEXSTORE_SYMBOL_PROPERTY_PROTOCOL_INTERFACE) + SymbolProperties |= (SymbolPropertySet)SymbolProperty::ProtocolInterface; + + return SymbolProperties; +} + +inline SymbolRoleSet getSymbolRoles(uint64_t Roles) { + SymbolRoleSet SymbolRoles = 0; + if (Roles & INDEXSTORE_SYMBOL_ROLE_DECLARATION) + SymbolRoles |= (SymbolRoleSet)SymbolRole::Declaration; + if (Roles & INDEXSTORE_SYMBOL_ROLE_DEFINITION) + SymbolRoles |= (SymbolRoleSet)SymbolRole::Definition; + if (Roles & INDEXSTORE_SYMBOL_ROLE_REFERENCE) + SymbolRoles |= (SymbolRoleSet)SymbolRole::Reference; + if (Roles & INDEXSTORE_SYMBOL_ROLE_READ) + SymbolRoles |= (SymbolRoleSet)SymbolRole::Read; + if (Roles & INDEXSTORE_SYMBOL_ROLE_WRITE) + SymbolRoles |= (SymbolRoleSet)SymbolRole::Write; + if (Roles & INDEXSTORE_SYMBOL_ROLE_CALL) + SymbolRoles |= (SymbolRoleSet)SymbolRole::Call; + if (Roles & INDEXSTORE_SYMBOL_ROLE_DYNAMIC) + SymbolRoles |= (SymbolRoleSet)SymbolRole::Dynamic; + if (Roles & INDEXSTORE_SYMBOL_ROLE_ADDRESSOF) + SymbolRoles |= (SymbolRoleSet)SymbolRole::AddressOf; + if (Roles & INDEXSTORE_SYMBOL_ROLE_IMPLICIT) + SymbolRoles |= (SymbolRoleSet)SymbolRole::Implicit; + if (Roles & INDEXSTORE_SYMBOL_ROLE_UNDEFINITION) + SymbolRoles |= (SymbolRoleSet)SymbolRole::Undefinition; + if (Roles & INDEXSTORE_SYMBOL_ROLE_REL_CHILDOF) + SymbolRoles |= (SymbolRoleSet)SymbolRole::RelationChildOf; + if (Roles & INDEXSTORE_SYMBOL_ROLE_REL_BASEOF) + SymbolRoles |= (SymbolRoleSet)SymbolRole::RelationBaseOf; + if (Roles & INDEXSTORE_SYMBOL_ROLE_REL_OVERRIDEOF) + SymbolRoles |= (SymbolRoleSet)SymbolRole::RelationOverrideOf; + if (Roles & INDEXSTORE_SYMBOL_ROLE_REL_RECEIVEDBY) + SymbolRoles |= (SymbolRoleSet)SymbolRole::RelationReceivedBy; + if (Roles & INDEXSTORE_SYMBOL_ROLE_REL_CALLEDBY) + SymbolRoles |= (SymbolRoleSet)SymbolRole::RelationCalledBy; + if (Roles & INDEXSTORE_SYMBOL_ROLE_REL_EXTENDEDBY) + SymbolRoles |= (SymbolRoleSet)SymbolRole::RelationExtendedBy; + if (Roles & INDEXSTORE_SYMBOL_ROLE_REL_ACCESSOROF) + SymbolRoles |= (SymbolRoleSet)SymbolRole::RelationAccessorOf; + if (Roles & INDEXSTORE_SYMBOL_ROLE_REL_CONTAINEDBY) + SymbolRoles |= (SymbolRoleSet)SymbolRole::RelationContainedBy; + if (Roles & INDEXSTORE_SYMBOL_ROLE_REL_IBTYPEOF) + SymbolRoles |= (SymbolRoleSet)SymbolRole::RelationIBTypeOf; + if (Roles & INDEXSTORE_SYMBOL_ROLE_REL_SPECIALIZATIONOF) + SymbolRoles |= (SymbolRoleSet)SymbolRole::RelationSpecializationOf; + + return SymbolRoles; +} + +inline indexstore_symbol_kind_t getIndexStoreKind(SymbolKind K) { + switch (K) { + case SymbolKind::Unknown: + return INDEXSTORE_SYMBOL_KIND_UNKNOWN; + case SymbolKind::Module: + return INDEXSTORE_SYMBOL_KIND_MODULE; + case SymbolKind::Namespace: + return INDEXSTORE_SYMBOL_KIND_NAMESPACE; + case SymbolKind::NamespaceAlias: + return INDEXSTORE_SYMBOL_KIND_NAMESPACEALIAS; + case SymbolKind::Macro: + return INDEXSTORE_SYMBOL_KIND_MACRO; + case SymbolKind::Enum: + return INDEXSTORE_SYMBOL_KIND_ENUM; + case SymbolKind::Struct: + return INDEXSTORE_SYMBOL_KIND_STRUCT; + case SymbolKind::Class: + return INDEXSTORE_SYMBOL_KIND_CLASS; + case SymbolKind::Protocol: + return INDEXSTORE_SYMBOL_KIND_PROTOCOL; + case SymbolKind::Extension: + return INDEXSTORE_SYMBOL_KIND_EXTENSION; + case SymbolKind::Union: + return INDEXSTORE_SYMBOL_KIND_UNION; + case SymbolKind::TypeAlias: + return INDEXSTORE_SYMBOL_KIND_TYPEALIAS; + case SymbolKind::Function: + return INDEXSTORE_SYMBOL_KIND_FUNCTION; + case SymbolKind::Variable: + return INDEXSTORE_SYMBOL_KIND_VARIABLE; + case SymbolKind::Field: + return INDEXSTORE_SYMBOL_KIND_FIELD; + case SymbolKind::EnumConstant: + return INDEXSTORE_SYMBOL_KIND_ENUMCONSTANT; + case SymbolKind::InstanceMethod: + return INDEXSTORE_SYMBOL_KIND_INSTANCEMETHOD; + case SymbolKind::ClassMethod: + return INDEXSTORE_SYMBOL_KIND_CLASSMETHOD; + case SymbolKind::StaticMethod: + return INDEXSTORE_SYMBOL_KIND_STATICMETHOD; + case SymbolKind::InstanceProperty: + return INDEXSTORE_SYMBOL_KIND_INSTANCEPROPERTY; + case SymbolKind::ClassProperty: + return INDEXSTORE_SYMBOL_KIND_CLASSPROPERTY; + case SymbolKind::StaticProperty: + return INDEXSTORE_SYMBOL_KIND_STATICPROPERTY; + case SymbolKind::Constructor: + return INDEXSTORE_SYMBOL_KIND_CONSTRUCTOR; + case SymbolKind::Destructor: + return INDEXSTORE_SYMBOL_KIND_DESTRUCTOR; + case SymbolKind::ConversionFunction: + return INDEXSTORE_SYMBOL_KIND_CONVERSIONFUNCTION; + case SymbolKind::Parameter: + return INDEXSTORE_SYMBOL_KIND_PARAMETER; + case SymbolKind::Using: + return INDEXSTORE_SYMBOL_KIND_USING; + case SymbolKind::CommentTag: + return INDEXSTORE_SYMBOL_KIND_COMMENTTAG; + } + llvm_unreachable("unexpected symbol kind"); +} + +inline indexstore_symbol_subkind_t getIndexStoreSubKind(SymbolSubKind K) { + switch (K) { + case SymbolSubKind::None: + return INDEXSTORE_SYMBOL_SUBKIND_NONE; + case SymbolSubKind::CXXCopyConstructor: + return INDEXSTORE_SYMBOL_SUBKIND_CXXCOPYCONSTRUCTOR; + case SymbolSubKind::CXXMoveConstructor: + return INDEXSTORE_SYMBOL_SUBKIND_CXXMOVECONSTRUCTOR; + case SymbolSubKind::AccessorGetter: + return INDEXSTORE_SYMBOL_SUBKIND_ACCESSORGETTER; + case SymbolSubKind::AccessorSetter: + return INDEXSTORE_SYMBOL_SUBKIND_ACCESSORSETTER; + case SymbolSubKind::UsingTypename: + return INDEXSTORE_SYMBOL_SUBKIND_USINGTYPENAME; + case SymbolSubKind::UsingValue: + return INDEXSTORE_SYMBOL_SUBKIND_USINGVALUE; + case SymbolSubKind::SwiftAccessorWillSet: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORWILLSET; + case SymbolSubKind::SwiftAccessorDidSet: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORDIDSET; + case SymbolSubKind::SwiftAccessorAddressor: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORADDRESSOR; + case SymbolSubKind::SwiftAccessorMutableAddressor: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORMUTABLEADDRESSOR; + case SymbolSubKind::SwiftAccessorRead: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORREAD; + case SymbolSubKind::SwiftAccessorModify: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORMODIFY; + case SymbolSubKind::SwiftExtensionOfStruct: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFSTRUCT; + case SymbolSubKind::SwiftExtensionOfClass: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFCLASS; + case SymbolSubKind::SwiftExtensionOfEnum: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFENUM; + case SymbolSubKind::SwiftExtensionOfProtocol: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFPROTOCOL; + case SymbolSubKind::SwiftPrefixOperator: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTPREFIXOPERATOR; + case SymbolSubKind::SwiftPostfixOperator: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTPOSTFIXOPERATOR; + case SymbolSubKind::SwiftInfixOperator: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTINFIXOPERATOR; + case SymbolSubKind::SwiftSubscript: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTSUBSCRIPT; + case SymbolSubKind::SwiftAssociatedType: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTASSOCIATEDTYPE; + case SymbolSubKind::SwiftGenericTypeParam: + return INDEXSTORE_SYMBOL_SUBKIND_SWIFTGENERICTYPEPARAM; + } + llvm_unreachable("unexpected symbol subkind"); +} + +inline indexstore_symbol_language_t getIndexStoreLang(SymbolLanguage L) { + switch (L) { + case SymbolLanguage::C: + return INDEXSTORE_SYMBOL_LANG_C; + case SymbolLanguage::ObjC: + return INDEXSTORE_SYMBOL_LANG_OBJC; + case SymbolLanguage::CXX: + return INDEXSTORE_SYMBOL_LANG_CXX; + case SymbolLanguage::Swift: + return INDEXSTORE_SYMBOL_LANG_SWIFT; + } + llvm_unreachable("unexpected symbol language"); +} + +inline uint64_t getIndexStoreProperties(SymbolPropertySet Props) { + uint64_t storeProp = 0; + applyForEachSymbolProperty(Props, [&](SymbolProperty prop) { + switch (prop) { + case SymbolProperty::Generic: + storeProp |= INDEXSTORE_SYMBOL_PROPERTY_GENERIC; + break; + case SymbolProperty::TemplatePartialSpecialization: + storeProp |= INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_PARTIAL_SPECIALIZATION; + break; + case SymbolProperty::TemplateSpecialization: + storeProp |= INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_SPECIALIZATION; + break; + case SymbolProperty::UnitTest: + storeProp |= INDEXSTORE_SYMBOL_PROPERTY_UNITTEST; + break; + case SymbolProperty::IBAnnotated: + storeProp |= INDEXSTORE_SYMBOL_PROPERTY_IBANNOTATED; + break; + case SymbolProperty::IBOutletCollection: + storeProp |= INDEXSTORE_SYMBOL_PROPERTY_IBOUTLETCOLLECTION; + break; + case SymbolProperty::GKInspectable: + storeProp |= INDEXSTORE_SYMBOL_PROPERTY_GKINSPECTABLE; + break; + case SymbolProperty::Local: + storeProp |= INDEXSTORE_SYMBOL_PROPERTY_LOCAL; + break; + case SymbolProperty::ProtocolInterface: + storeProp |= INDEXSTORE_SYMBOL_PROPERTY_PROTOCOL_INTERFACE; + break; + } + }); + return storeProp; +} + +inline uint64_t getIndexStoreRoles(SymbolRoleSet Roles) { + uint64_t storeRoles = 0; + applyForEachSymbolRole(Roles, [&](SymbolRole role) { + switch (role) { + case SymbolRole::Declaration: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_DECLARATION; + break; + case SymbolRole::Definition: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_DEFINITION; + break; + case SymbolRole::Reference: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_REFERENCE; + break; + case SymbolRole::Read: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_READ; + break; + case SymbolRole::Write: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_WRITE; + break; + case SymbolRole::Call: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_CALL; + break; + case SymbolRole::Dynamic: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_DYNAMIC; + break; + case SymbolRole::AddressOf: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_ADDRESSOF; + break; + case SymbolRole::Implicit: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_IMPLICIT; + break; + case SymbolRole::Undefinition: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_UNDEFINITION; + break; + case SymbolRole::RelationChildOf: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_CHILDOF; + break; + case SymbolRole::RelationBaseOf: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_BASEOF; + break; + case SymbolRole::RelationOverrideOf: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_OVERRIDEOF; + break; + case SymbolRole::RelationReceivedBy: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_RECEIVEDBY; + break; + case SymbolRole::RelationCalledBy: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_CALLEDBY; + break; + case SymbolRole::RelationExtendedBy: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_EXTENDEDBY; + break; + case SymbolRole::RelationAccessorOf: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_ACCESSOROF; + break; + case SymbolRole::RelationContainedBy: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_CONTAINEDBY; + break; + case SymbolRole::RelationIBTypeOf: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_IBTYPEOF; + break; + case SymbolRole::RelationSpecializationOf: + storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_SPECIALIZATIONOF; + break; + } + }); + return storeRoles; +} + +} // end namespace index +} // end namespace clang0 + +#endif Index: clang/include/indexstore/IndexStoreCXX.h =================================================================== --- /dev/null +++ clang/include/indexstore/IndexStoreCXX.h @@ -0,0 +1,536 @@ +//===--- IndexStoreCXX.h - C++ wrapper for the Index Store C API. ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Header-only C++ wrapper for the Index Store C API. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEXSTORE_INDEXSTORECXX_H +#define LLVM_CLANG_INDEXSTORE_INDEXSTORECXX_H + +#include "indexstore/indexstore.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include + +namespace indexstore { + using llvm::ArrayRef; + using llvm::Optional; + using llvm::StringRef; + +static inline StringRef stringFromIndexStoreStringRef(indexstore_string_ref_t str) { + return StringRef(str.data, str.length); +} + +template +static inline Ret functionPtrFromFunctionRef(void *ctx, Params ...params) { + auto fn = (llvm::function_ref *)ctx; + return (*fn)(std::forward(params)...); +} + +class IndexRecordSymbol { + indexstore_symbol_t obj; + friend class IndexRecordReader; + +public: + IndexRecordSymbol(indexstore_symbol_t obj) : obj(obj) {} + + indexstore_symbol_language_t getLanguage() { + return indexstore_symbol_get_language(obj); + } + indexstore_symbol_kind_t getKind() { return indexstore_symbol_get_kind(obj); } + indexstore_symbol_subkind_t getSubKind() { return indexstore_symbol_get_subkind(obj); } + uint64_t getProperties() { + return indexstore_symbol_get_properties(obj); + } + uint64_t getRoles() { return indexstore_symbol_get_roles(obj); } + uint64_t getRelatedRoles() { return indexstore_symbol_get_related_roles(obj); } + StringRef getName() { return stringFromIndexStoreStringRef(indexstore_symbol_get_name(obj)); } + StringRef getUSR() { return stringFromIndexStoreStringRef(indexstore_symbol_get_usr(obj)); } + StringRef getCodegenName() { return stringFromIndexStoreStringRef(indexstore_symbol_get_codegen_name(obj)); } +}; + +class IndexSymbolRelation { + indexstore_symbol_relation_t obj; + +public: + IndexSymbolRelation(indexstore_symbol_relation_t obj) : obj(obj) {} + + uint64_t getRoles() { return indexstore_symbol_relation_get_roles(obj); } + IndexRecordSymbol getSymbol() { return indexstore_symbol_relation_get_symbol(obj); } +}; + +class IndexRecordOccurrence { + indexstore_occurrence_t obj; + +public: + IndexRecordOccurrence(indexstore_occurrence_t obj) : obj(obj) {} + + IndexRecordSymbol getSymbol() { return indexstore_occurrence_get_symbol(obj); } + uint64_t getRoles() { return indexstore_occurrence_get_roles(obj); } + + bool foreachRelation(llvm::function_ref receiver) { +#if INDEXSTORE_HAS_BLOCKS + return indexstore_occurrence_relations_apply(obj, ^bool(indexstore_symbol_relation_t sym_rel) { + return receiver(sym_rel); + }); +#else + return indexstore_occurrence_relations_apply_f(obj, &receiver, functionPtrFromFunctionRef); +#endif + } + + std::pair getLineCol() { + unsigned line, col; + indexstore_occurrence_get_line_col(obj, &line, &col); + return std::make_pair(line, col); + } +}; + +class IndexStore; +typedef std::shared_ptr IndexStoreRef; + +class IndexStore { + indexstore_t obj; + friend class IndexRecordReader; + friend class IndexUnitReader; + +public: + IndexStore(StringRef path, std::string &error) { + llvm::SmallString<64> buf = path; + indexstore_error_t c_err = nullptr; + obj = indexstore_store_create(buf.c_str(), &c_err); + if (c_err) { + error = indexstore_error_get_description(c_err); + indexstore_error_dispose(c_err); + } + } + + IndexStore(IndexStore &&other) : obj(other.obj) { + other.obj = nullptr; + } + + ~IndexStore() { + indexstore_store_dispose(obj); + } + + static IndexStoreRef create(StringRef path, std::string &error) { + auto storeRef = std::make_shared(path, error); + if (storeRef->isInvalid()) + return nullptr; + return storeRef; + } + + static unsigned formatVersion() { + return indexstore_format_version(); + } + + bool isValid() const { return obj; } + bool isInvalid() const { return !isValid(); } + explicit operator bool() const { return isValid(); } + + bool foreachUnit(bool sorted, llvm::function_ref receiver) { +#if INDEXSTORE_HAS_BLOCKS + return indexstore_store_units_apply(obj, sorted, ^bool(indexstore_string_ref_t unit_name) { + return receiver(stringFromIndexStoreStringRef(unit_name)); + }); +#else + return indexstore_store_units_apply_f(obj, sorted, &receiver, functionPtrFromFunctionRef); +#endif + } + + class UnitEvent { + indexstore_unit_event_t obj; + public: + UnitEvent(indexstore_unit_event_t obj) : obj(obj) {} + + enum class Kind { + Added, + Removed, + Modified, + DirectoryDeleted, + }; + Kind getKind() const { + indexstore_unit_event_kind_t c_k = indexstore_unit_event_get_kind(obj); + Kind K; + switch (c_k) { + case INDEXSTORE_UNIT_EVENT_ADDED: K = Kind::Added; break; + case INDEXSTORE_UNIT_EVENT_REMOVED: K = Kind::Removed; break; + case INDEXSTORE_UNIT_EVENT_MODIFIED: K = Kind::Modified; break; + case INDEXSTORE_UNIT_EVENT_DIRECTORY_DELETED: K = Kind::DirectoryDeleted; break; + } + return K; + } + + StringRef getUnitName() const { + return stringFromIndexStoreStringRef(indexstore_unit_event_get_unit_name(obj)); + } + + timespec getModificationTime() const { return indexstore_unit_event_get_modification_time(obj); } + }; + + class UnitEventNotification { + indexstore_unit_event_notification_t obj; + public: + UnitEventNotification(indexstore_unit_event_notification_t obj) : obj(obj) {} + + bool isInitial() const { return indexstore_unit_event_notification_is_initial(obj); } + size_t getEventsCount() const { return indexstore_unit_event_notification_get_events_count(obj); } + UnitEvent getEvent(size_t index) const { return indexstore_unit_event_notification_get_event(obj, index); } + }; + + typedef std::function UnitEventHandler; + + void setUnitEventHandler(UnitEventHandler handler) { +#if INDEXSTORE_HAS_BLOCKS + if (!handler) { + indexstore_store_set_unit_event_handler(obj, nullptr); + return; + } + + indexstore_store_set_unit_event_handler(obj, ^(indexstore_unit_event_notification_t evt_note) { + handler(UnitEventNotification(evt_note)); + }); +#else + if (!handler) { + indexstore_store_set_unit_event_handler_f(obj, nullptr, nullptr, nullptr); + return; + } + + auto fnPtr = new UnitEventHandler(handler); + indexstore_store_set_unit_event_handler_f(obj, fnPtr, event_handler, event_handler_finalizer); +#endif + } + +private: + static void event_handler(void *ctx, indexstore_unit_event_notification_t evt) { + auto fnPtr = (UnitEventHandler*)ctx; + (*fnPtr)(evt); + } + static void event_handler_finalizer(void *ctx) { + auto fnPtr = (UnitEventHandler*)ctx; + delete fnPtr; + } + +public: + bool startEventListening(bool waitInitialSync, std::string &error) { + indexstore_unit_event_listen_options_t opts; + opts.wait_initial_sync = waitInitialSync; + indexstore_error_t c_err = nullptr; + bool ret = indexstore_store_start_unit_event_listening(obj, &opts, sizeof(opts), &c_err); + if (c_err) { + error = indexstore_error_get_description(c_err); + indexstore_error_dispose(c_err); + } + return ret; + } + + void stopEventListening() { + return indexstore_store_stop_unit_event_listening(obj); + } + + void discardUnit(StringRef UnitName) { + llvm::SmallString<64> buf = UnitName; + indexstore_store_discard_unit(obj, buf.c_str()); + } + + void discardRecord(StringRef RecordName) { + llvm::SmallString<64> buf = RecordName; + indexstore_store_discard_record(obj, buf.c_str()); + } + + void getUnitNameFromOutputPath(StringRef outputPath, llvm::SmallVectorImpl &nameBuf) { + llvm::SmallString<256> buf = outputPath; + llvm::SmallString<64> unitName; + unitName.resize(64); + size_t nameLen = indexstore_store_get_unit_name_from_output_path(obj, buf.c_str(), unitName.data(), unitName.size()); + if (nameLen+1 > unitName.size()) { + unitName.resize(nameLen+1); + indexstore_store_get_unit_name_from_output_path(obj, buf.c_str(), unitName.data(), unitName.size()); + } + nameBuf.append(unitName.begin(), unitName.begin()+nameLen); + } + + llvm::Optional + getUnitModificationTime(StringRef unitName, std::string &error) { + llvm::SmallString<64> buf = unitName; + int64_t seconds, nanoseconds; + indexstore_error_t c_err = nullptr; + bool err = indexstore_store_get_unit_modification_time(obj, buf.c_str(), + &seconds, &nanoseconds, &c_err); + if (err && c_err) { + error = indexstore_error_get_description(c_err); + indexstore_error_dispose(c_err); + return llvm::None; + } + timespec ts; + ts.tv_sec = seconds; + ts.tv_nsec = nanoseconds; + return ts; + } + + void purgeStaleData() { + indexstore_store_purge_stale_data(obj); + } +}; + +class IndexRecordReader { + indexstore_record_reader_t obj; + +public: + IndexRecordReader(IndexStore &store, StringRef recordName, std::string &error) { + llvm::SmallString<64> buf = recordName; + indexstore_error_t c_err = nullptr; + obj = indexstore_record_reader_create(store.obj, buf.c_str(), &c_err); + if (c_err) { + error = indexstore_error_get_description(c_err); + indexstore_error_dispose(c_err); + } + } + + IndexRecordReader(IndexRecordReader &&other) : obj(other.obj) { + other.obj = nullptr; + } + + ~IndexRecordReader() { + indexstore_record_reader_dispose(obj); + } + + bool isValid() const { return obj; } + bool isInvalid() const { return !isValid(); } + explicit operator bool() const { return isValid(); } + + /// Goes through and passes record decls, after filtering using a \c Checker + /// function. + /// + /// Resulting decls can be used as filter for \c foreachOccurrence. This + /// allows allocating memory only for the record decls that the caller is + /// interested in. + bool searchSymbols(llvm::function_ref filter, + llvm::function_ref receiver) { +#if INDEXSTORE_HAS_BLOCKS + return indexstore_record_reader_search_symbols(obj, ^bool(indexstore_symbol_t symbol, bool *stop) { + return filter(symbol, *stop); + }, ^(indexstore_symbol_t symbol) { + receiver(symbol); + }); +#else + return indexstore_record_reader_search_symbols_f(obj, &filter, functionPtrFromFunctionRef, + &receiver, functionPtrFromFunctionRef); +#endif + } + + bool foreachSymbol(bool noCache, llvm::function_ref receiver) { +#if INDEXSTORE_HAS_BLOCKS + return indexstore_record_reader_symbols_apply(obj, noCache, ^bool(indexstore_symbol_t sym) { + return receiver(sym); + }); +#else + return indexstore_record_reader_symbols_apply_f(obj, noCache, &receiver, functionPtrFromFunctionRef); +#endif + } + + /// \param DeclsFilter if non-empty indicates the list of decls that we want + /// to get occurrences for. An empty array indicates that we want occurrences + /// for all decls. + /// \param RelatedDeclsFilter Same as \c DeclsFilter but for related decls. + bool foreachOccurrence(ArrayRef symbolsFilter, + ArrayRef relatedSymbolsFilter, + llvm::function_ref receiver) { + llvm::SmallVector c_symbolsFilter; + c_symbolsFilter.reserve(symbolsFilter.size()); + for (IndexRecordSymbol sym : symbolsFilter) { + c_symbolsFilter.push_back(sym.obj); + } + llvm::SmallVector c_relatedSymbolsFilter; + c_relatedSymbolsFilter.reserve(relatedSymbolsFilter.size()); + for (IndexRecordSymbol sym : relatedSymbolsFilter) { + c_relatedSymbolsFilter.push_back(sym.obj); + } +#if INDEXSTORE_HAS_BLOCKS + return indexstore_record_reader_occurrences_of_symbols_apply(obj, + c_symbolsFilter.data(), c_symbolsFilter.size(), + c_relatedSymbolsFilter.data(), + c_relatedSymbolsFilter.size(), + ^bool(indexstore_occurrence_t occur) { + return receiver(occur); + }); +#else + return indexstore_record_reader_occurrences_of_symbols_apply_f(obj, + c_symbolsFilter.data(), c_symbolsFilter.size(), + c_relatedSymbolsFilter.data(), + c_relatedSymbolsFilter.size(), + &receiver, functionPtrFromFunctionRef); +#endif + } + + bool foreachOccurrence( + llvm::function_ref receiver) { +#if INDEXSTORE_HAS_BLOCKS + return indexstore_record_reader_occurrences_apply(obj, ^bool(indexstore_occurrence_t occur) { + return receiver(occur); + }); +#else + return indexstore_record_reader_occurrences_apply_f(obj, &receiver, functionPtrFromFunctionRef); +#endif + } + + bool foreachOccurrenceInLineRange(unsigned lineStart, unsigned lineEnd, + llvm::function_ref receiver) { +#if INDEXSTORE_HAS_BLOCKS + return indexstore_record_reader_occurrences_in_line_range_apply(obj, + lineStart, + lineEnd, + ^bool(indexstore_occurrence_t occur) { + return receiver(occur); + }); +#else + return indexstore_record_reader_occurrences_in_line_range_apply_f(obj, + lineStart, + lineEnd, + &receiver, functionPtrFromFunctionRef); +#endif + } +}; + +class IndexUnitDependency { + indexstore_unit_dependency_t obj; + friend class IndexUnitReader; + +public: + IndexUnitDependency(indexstore_unit_dependency_t obj) : obj(obj) {} + + enum class DependencyKind { + Unit, + Record, + File, + }; + DependencyKind getKind() { + switch (indexstore_unit_dependency_get_kind(obj)) { + case INDEXSTORE_UNIT_DEPENDENCY_UNIT: return DependencyKind::Unit; + case INDEXSTORE_UNIT_DEPENDENCY_RECORD: return DependencyKind::Record; + case INDEXSTORE_UNIT_DEPENDENCY_FILE: return DependencyKind::File; + } + } + bool isSystem() { return indexstore_unit_dependency_is_system(obj); } + StringRef getName() { return stringFromIndexStoreStringRef(indexstore_unit_dependency_get_name(obj)); } + StringRef getFilePath() { return stringFromIndexStoreStringRef(indexstore_unit_dependency_get_filepath(obj)); } + StringRef getModuleName() { return stringFromIndexStoreStringRef(indexstore_unit_dependency_get_modulename(obj)); } + +}; + +class IndexUnitInclude { + indexstore_unit_include_t obj; + friend class IndexUnitReader; + +public: + IndexUnitInclude(indexstore_unit_include_t obj) : obj(obj) {} + + StringRef getSourcePath() { + return stringFromIndexStoreStringRef(indexstore_unit_include_get_source_path(obj)); + } + StringRef getTargetPath() { + return stringFromIndexStoreStringRef(indexstore_unit_include_get_target_path(obj)); + } + unsigned getSourceLine() { + return indexstore_unit_include_get_source_line(obj); + } +}; + +class IndexUnitReader { + indexstore_unit_reader_t obj; + +public: + IndexUnitReader(IndexStore &store, StringRef unitName, std::string &error) { + llvm::SmallString<64> buf = unitName; + indexstore_error_t c_err = nullptr; + obj = indexstore_unit_reader_create(store.obj, buf.c_str(), &c_err); + if (c_err) { + error = indexstore_error_get_description(c_err); + indexstore_error_dispose(c_err); + } + } + + IndexUnitReader(IndexUnitReader &&other) : obj(other.obj) { + other.obj = nullptr; + } + + ~IndexUnitReader() { + indexstore_unit_reader_dispose(obj); + } + + bool isValid() const { return obj; } + bool isInvalid() const { return !isValid(); } + explicit operator bool() const { return isValid(); } + + StringRef getProviderIdentifier() { + return stringFromIndexStoreStringRef(indexstore_unit_reader_get_provider_identifier(obj)); + } + StringRef getProviderVersion() { + return stringFromIndexStoreStringRef(indexstore_unit_reader_get_provider_version(obj)); + } + + timespec getModificationTime() { + int64_t seconds, nanoseconds; + indexstore_unit_reader_get_modification_time(obj, &seconds, &nanoseconds); + timespec ts; + ts.tv_sec = seconds; + ts.tv_nsec = nanoseconds; + return ts; + } + + bool isSystemUnit() { return indexstore_unit_reader_is_system_unit(obj); } + bool isModuleUnit() { return indexstore_unit_reader_is_module_unit(obj); } + bool isDebugCompilation() { return indexstore_unit_reader_is_debug_compilation(obj); } + bool hasMainFile() { return indexstore_unit_reader_has_main_file(obj); } + + StringRef getMainFilePath() { + return stringFromIndexStoreStringRef(indexstore_unit_reader_get_main_file(obj)); + } + StringRef getModuleName() { + return stringFromIndexStoreStringRef(indexstore_unit_reader_get_module_name(obj)); + } + StringRef getWorkingDirectory() { + return stringFromIndexStoreStringRef(indexstore_unit_reader_get_working_dir(obj)); + } + StringRef getOutputFile() { + return stringFromIndexStoreStringRef(indexstore_unit_reader_get_output_file(obj)); + } + StringRef getSysrootPath() { + return stringFromIndexStoreStringRef(indexstore_unit_reader_get_sysroot_path(obj)); + } + StringRef getTarget() { + return stringFromIndexStoreStringRef(indexstore_unit_reader_get_target(obj)); + } + + bool foreachDependency(llvm::function_ref receiver) { +#if INDEXSTORE_HAS_BLOCKS + return indexstore_unit_reader_dependencies_apply(obj, ^bool(indexstore_unit_dependency_t dep) { + return receiver(dep); + }); +#else + return indexstore_unit_reader_dependencies_apply_f(obj, &receiver, functionPtrFromFunctionRef); +#endif + } + + bool foreachInclude(llvm::function_ref receiver) { +#if INDEXSTORE_HAS_BLOCKS + return indexstore_unit_reader_includes_apply(obj, ^bool(indexstore_unit_include_t inc) { + return receiver(inc); + }); +#else + return indexstore_unit_reader_includes_apply_f(obj, &receiver, functionPtrFromFunctionRef); +#endif + } +}; + +} // namespace indexstore + +#endif Index: clang/include/indexstore/indexstore.h =================================================================== --- /dev/null +++ clang/include/indexstore/indexstore.h @@ -0,0 +1,558 @@ +/*===-- indexstore/indexstore.h - Index Store C API ----------------- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides a C API for the index store. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_CLANG_C_INDEXSTORE_INDEXSTORE_H +#define LLVM_CLANG_C_INDEXSTORE_INDEXSTORE_H + +#include +#include +#include +#include + +/** + * \brief The version constants for the Index Store C API. + * INDEXSTORE_VERSION_MINOR should increase when there are API additions. + * INDEXSTORE_VERSION_MAJOR is intended for "major" source/ABI breaking changes. + */ +#define INDEXSTORE_VERSION_MAJOR 0 +#define INDEXSTORE_VERSION_MINOR 11 + +#define INDEXSTORE_VERSION_ENCODE(major, minor) ( \ + ((major) * 10000) \ + + ((minor) * 1)) + +#define INDEXSTORE_VERSION INDEXSTORE_VERSION_ENCODE( \ + INDEXSTORE_VERSION_MAJOR, \ + INDEXSTORE_VERSION_MINOR ) + +#define INDEXSTORE_VERSION_STRINGIZE_(major, minor) \ + #major"."#minor +#define INDEXSTORE_VERSION_STRINGIZE(major, minor) \ + INDEXSTORE_VERSION_STRINGIZE_(major, minor) + +#define INDEXSTORE_VERSION_STRING INDEXSTORE_VERSION_STRINGIZE( \ + INDEXSTORE_VERSION_MAJOR, \ + INDEXSTORE_VERSION_MINOR) + +#ifdef __cplusplus +# define INDEXSTORE_BEGIN_DECLS extern "C" { +# define INDEXSTORE_END_DECLS } +#else +# define INDEXSTORE_BEGIN_DECLS +# define INDEXSTORE_END_DECLS +#endif + +#ifndef INDEXSTORE_PUBLIC +# ifdef _WIN32 +# ifdef IndexStore_EXPORTS +# define INDEXSTORE_PUBLIC __declspec(dllexport) +# else +# define INDEXSTORE_PUBLIC __declspec(dllimport) +# endif +# else +# define INDEXSTORE_PUBLIC +# endif +#endif + +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +#ifndef __has_attribute +# define __has_attribute(x) 0 +#endif + +#if __has_feature(blocks) +# define INDEXSTORE_HAS_BLOCKS 1 +#else +# define INDEXSTORE_HAS_BLOCKS 0 +#endif + +#if __has_attribute(noescape) +# define INDEXSTORE_NOESCAPE __attribute__((noescape)) +#else +# define INDEXSTORE_NOESCAPE +#endif + +INDEXSTORE_BEGIN_DECLS + +typedef void *indexstore_error_t; + +INDEXSTORE_PUBLIC const char * +indexstore_error_get_description(indexstore_error_t); + +INDEXSTORE_PUBLIC void +indexstore_error_dispose(indexstore_error_t); + +typedef struct { + const char *data; + size_t length; +} indexstore_string_ref_t; + +INDEXSTORE_PUBLIC unsigned +indexstore_format_version(void); + +typedef void *indexstore_t; + +INDEXSTORE_PUBLIC indexstore_t +indexstore_store_create(const char *store_path, indexstore_error_t *error); + +INDEXSTORE_PUBLIC void +indexstore_store_dispose(indexstore_t); + +#if INDEXSTORE_HAS_BLOCKS +INDEXSTORE_PUBLIC bool +indexstore_store_units_apply(indexstore_t, unsigned sorted, + INDEXSTORE_NOESCAPE bool(^applier)(indexstore_string_ref_t unit_name)); +#endif + +INDEXSTORE_PUBLIC bool +indexstore_store_units_apply_f(indexstore_t, unsigned sorted, + void *context, + INDEXSTORE_NOESCAPE bool(*applier)(void *context, indexstore_string_ref_t unit_name)); + +typedef void *indexstore_unit_event_notification_t; +typedef void *indexstore_unit_event_t; + +INDEXSTORE_PUBLIC size_t +indexstore_unit_event_notification_get_events_count(indexstore_unit_event_notification_t); + +INDEXSTORE_PUBLIC indexstore_unit_event_t +indexstore_unit_event_notification_get_event(indexstore_unit_event_notification_t, size_t index); + +INDEXSTORE_PUBLIC bool +indexstore_unit_event_notification_is_initial(indexstore_unit_event_notification_t); + +typedef enum { + INDEXSTORE_UNIT_EVENT_ADDED = 1, + INDEXSTORE_UNIT_EVENT_REMOVED = 2, + INDEXSTORE_UNIT_EVENT_MODIFIED = 3, + INDEXSTORE_UNIT_EVENT_DIRECTORY_DELETED = 4, +} indexstore_unit_event_kind_t; + +INDEXSTORE_PUBLIC indexstore_unit_event_kind_t +indexstore_unit_event_get_kind(indexstore_unit_event_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_event_get_unit_name(indexstore_unit_event_t); + +INDEXSTORE_PUBLIC struct timespec +indexstore_unit_event_get_modification_time(indexstore_unit_event_t); + +#if INDEXSTORE_HAS_BLOCKS +typedef void (^indexstore_unit_event_handler_t)(indexstore_unit_event_notification_t); + +INDEXSTORE_PUBLIC void +indexstore_store_set_unit_event_handler(indexstore_t, + indexstore_unit_event_handler_t handler); +#endif + +INDEXSTORE_PUBLIC void +indexstore_store_set_unit_event_handler_f(indexstore_t, void *context, + void(*handler)(void *context, indexstore_unit_event_notification_t), + void(*finalizer)(void *context)); + +typedef struct { + /// If true, \c indexstore_store_start_unit_event_listening will block until + /// the initial set of units is passed to the unit event handler, otherwise + /// the function will return and the initial set will be passed asynchronously. + bool wait_initial_sync; +} indexstore_unit_event_listen_options_t; + +INDEXSTORE_PUBLIC bool +indexstore_store_start_unit_event_listening(indexstore_t, + indexstore_unit_event_listen_options_t *, + size_t listen_options_struct_size, + indexstore_error_t *error); + +INDEXSTORE_PUBLIC void +indexstore_store_stop_unit_event_listening(indexstore_t); + +INDEXSTORE_PUBLIC void +indexstore_store_discard_unit(indexstore_t, const char *unit_name); + +INDEXSTORE_PUBLIC void +indexstore_store_discard_record(indexstore_t, const char *record_name); + +INDEXSTORE_PUBLIC void +indexstore_store_purge_stale_data(indexstore_t); + +/// Determines the unit name from the \c output_path and writes it out in the +/// \c name_buf buffer. It doesn't write more than \c buf_size. +/// \returns the length of the name. If this is larger than \c buf_size, the +/// caller should call the function again with a buffer of the appropriate size. +INDEXSTORE_PUBLIC size_t +indexstore_store_get_unit_name_from_output_path(indexstore_t store, + const char *output_path, + char *name_buf, + size_t buf_size); + +/// \returns true if an error occurred, false otherwise. +INDEXSTORE_PUBLIC bool +indexstore_store_get_unit_modification_time(indexstore_t store, + const char *unit_name, + int64_t *seconds, + int64_t *nanoseconds, + indexstore_error_t *error); + +typedef void *indexstore_symbol_t; + +typedef enum { + INDEXSTORE_SYMBOL_KIND_UNKNOWN = 0, + INDEXSTORE_SYMBOL_KIND_MODULE = 1, + INDEXSTORE_SYMBOL_KIND_NAMESPACE = 2, + INDEXSTORE_SYMBOL_KIND_NAMESPACEALIAS = 3, + INDEXSTORE_SYMBOL_KIND_MACRO = 4, + INDEXSTORE_SYMBOL_KIND_ENUM = 5, + INDEXSTORE_SYMBOL_KIND_STRUCT = 6, + INDEXSTORE_SYMBOL_KIND_CLASS = 7, + INDEXSTORE_SYMBOL_KIND_PROTOCOL = 8, + INDEXSTORE_SYMBOL_KIND_EXTENSION = 9, + INDEXSTORE_SYMBOL_KIND_UNION = 10, + INDEXSTORE_SYMBOL_KIND_TYPEALIAS = 11, + INDEXSTORE_SYMBOL_KIND_FUNCTION = 12, + INDEXSTORE_SYMBOL_KIND_VARIABLE = 13, + INDEXSTORE_SYMBOL_KIND_FIELD = 14, + INDEXSTORE_SYMBOL_KIND_ENUMCONSTANT = 15, + INDEXSTORE_SYMBOL_KIND_INSTANCEMETHOD = 16, + INDEXSTORE_SYMBOL_KIND_CLASSMETHOD = 17, + INDEXSTORE_SYMBOL_KIND_STATICMETHOD = 18, + INDEXSTORE_SYMBOL_KIND_INSTANCEPROPERTY = 19, + INDEXSTORE_SYMBOL_KIND_CLASSPROPERTY = 20, + INDEXSTORE_SYMBOL_KIND_STATICPROPERTY = 21, + INDEXSTORE_SYMBOL_KIND_CONSTRUCTOR = 22, + INDEXSTORE_SYMBOL_KIND_DESTRUCTOR = 23, + INDEXSTORE_SYMBOL_KIND_CONVERSIONFUNCTION = 24, + INDEXSTORE_SYMBOL_KIND_PARAMETER = 25, + INDEXSTORE_SYMBOL_KIND_USING = 26, + + INDEXSTORE_SYMBOL_KIND_COMMENTTAG = 1000, +} indexstore_symbol_kind_t; + +typedef enum { + INDEXSTORE_SYMBOL_SUBKIND_NONE = 0, + INDEXSTORE_SYMBOL_SUBKIND_CXXCOPYCONSTRUCTOR = 1, + INDEXSTORE_SYMBOL_SUBKIND_CXXMOVECONSTRUCTOR = 2, + INDEXSTORE_SYMBOL_SUBKIND_ACCESSORGETTER = 3, + INDEXSTORE_SYMBOL_SUBKIND_ACCESSORSETTER = 4, + INDEXSTORE_SYMBOL_SUBKIND_USINGTYPENAME = 5, + INDEXSTORE_SYMBOL_SUBKIND_USINGVALUE = 6, + + INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORWILLSET = 1000, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORDIDSET = 1001, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORADDRESSOR = 1002, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORMUTABLEADDRESSOR = 1003, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFSTRUCT = 1004, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFCLASS = 1005, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFENUM = 1006, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFPROTOCOL = 1007, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTPREFIXOPERATOR = 1008, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTPOSTFIXOPERATOR = 1009, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTINFIXOPERATOR = 1010, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTSUBSCRIPT = 1011, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTASSOCIATEDTYPE = 1012, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTGENERICTYPEPARAM = 1013, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORREAD = 1014, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORMODIFY = 1015, +} indexstore_symbol_subkind_t; + +typedef enum { + INDEXSTORE_SYMBOL_PROPERTY_GENERIC = 1 << 0, + INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_PARTIAL_SPECIALIZATION = 1 << 1, + INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_SPECIALIZATION = 1 << 2, + INDEXSTORE_SYMBOL_PROPERTY_UNITTEST = 1 << 3, + INDEXSTORE_SYMBOL_PROPERTY_IBANNOTATED = 1 << 4, + INDEXSTORE_SYMBOL_PROPERTY_IBOUTLETCOLLECTION = 1 << 5, + INDEXSTORE_SYMBOL_PROPERTY_GKINSPECTABLE = 1 << 6, + INDEXSTORE_SYMBOL_PROPERTY_LOCAL = 1 << 7, + INDEXSTORE_SYMBOL_PROPERTY_PROTOCOL_INTERFACE = 1 << 8, +} indexstore_symbol_property_t; + +typedef enum { + INDEXSTORE_SYMBOL_LANG_C = 0, + INDEXSTORE_SYMBOL_LANG_OBJC = 1, + INDEXSTORE_SYMBOL_LANG_CXX = 2, + + INDEXSTORE_SYMBOL_LANG_SWIFT = 100, +} indexstore_symbol_language_t; + +typedef enum { + INDEXSTORE_SYMBOL_ROLE_DECLARATION = 1 << 0, + INDEXSTORE_SYMBOL_ROLE_DEFINITION = 1 << 1, + INDEXSTORE_SYMBOL_ROLE_REFERENCE = 1 << 2, + INDEXSTORE_SYMBOL_ROLE_READ = 1 << 3, + INDEXSTORE_SYMBOL_ROLE_WRITE = 1 << 4, + INDEXSTORE_SYMBOL_ROLE_CALL = 1 << 5, + INDEXSTORE_SYMBOL_ROLE_DYNAMIC = 1 << 6, + INDEXSTORE_SYMBOL_ROLE_ADDRESSOF = 1 << 7, + INDEXSTORE_SYMBOL_ROLE_IMPLICIT = 1 << 8, + INDEXSTORE_SYMBOL_ROLE_UNDEFINITION = 1 << 19, + + // Relation roles. + INDEXSTORE_SYMBOL_ROLE_REL_CHILDOF = 1 << 9, + INDEXSTORE_SYMBOL_ROLE_REL_BASEOF = 1 << 10, + INDEXSTORE_SYMBOL_ROLE_REL_OVERRIDEOF = 1 << 11, + INDEXSTORE_SYMBOL_ROLE_REL_RECEIVEDBY = 1 << 12, + INDEXSTORE_SYMBOL_ROLE_REL_CALLEDBY = 1 << 13, + INDEXSTORE_SYMBOL_ROLE_REL_EXTENDEDBY = 1 << 14, + INDEXSTORE_SYMBOL_ROLE_REL_ACCESSOROF = 1 << 15, + INDEXSTORE_SYMBOL_ROLE_REL_CONTAINEDBY = 1 << 16, + INDEXSTORE_SYMBOL_ROLE_REL_IBTYPEOF = 1 << 17, + INDEXSTORE_SYMBOL_ROLE_REL_SPECIALIZATIONOF = 1 << 18, +} indexstore_symbol_role_t; + +INDEXSTORE_PUBLIC indexstore_symbol_language_t +indexstore_symbol_get_language(indexstore_symbol_t); + +INDEXSTORE_PUBLIC indexstore_symbol_kind_t +indexstore_symbol_get_kind(indexstore_symbol_t); + +INDEXSTORE_PUBLIC indexstore_symbol_subkind_t +indexstore_symbol_get_subkind(indexstore_symbol_t); + +INDEXSTORE_PUBLIC uint64_t +indexstore_symbol_get_properties(indexstore_symbol_t); + +INDEXSTORE_PUBLIC uint64_t +indexstore_symbol_get_roles(indexstore_symbol_t); + +INDEXSTORE_PUBLIC uint64_t +indexstore_symbol_get_related_roles(indexstore_symbol_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_symbol_get_name(indexstore_symbol_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_symbol_get_usr(indexstore_symbol_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_symbol_get_codegen_name(indexstore_symbol_t); + +typedef void *indexstore_symbol_relation_t; + +INDEXSTORE_PUBLIC uint64_t +indexstore_symbol_relation_get_roles(indexstore_symbol_relation_t); + +INDEXSTORE_PUBLIC indexstore_symbol_t +indexstore_symbol_relation_get_symbol(indexstore_symbol_relation_t); + +typedef void *indexstore_occurrence_t; + +INDEXSTORE_PUBLIC indexstore_symbol_t +indexstore_occurrence_get_symbol(indexstore_occurrence_t); + +#if INDEXSTORE_HAS_BLOCKS +INDEXSTORE_PUBLIC bool +indexstore_occurrence_relations_apply(indexstore_occurrence_t, + INDEXSTORE_NOESCAPE bool(^applier)(indexstore_symbol_relation_t symbol_rel)); +#endif + +INDEXSTORE_PUBLIC bool +indexstore_occurrence_relations_apply_f(indexstore_occurrence_t, + void *context, + INDEXSTORE_NOESCAPE bool(*applier)(void *context, indexstore_symbol_relation_t symbol_rel)); + +INDEXSTORE_PUBLIC uint64_t +indexstore_occurrence_get_roles(indexstore_occurrence_t); + +INDEXSTORE_PUBLIC void +indexstore_occurrence_get_line_col(indexstore_occurrence_t, + unsigned *line, unsigned *column); + +typedef void *indexstore_record_reader_t; + +INDEXSTORE_PUBLIC indexstore_record_reader_t +indexstore_record_reader_create(indexstore_t store, const char *record_name, + indexstore_error_t *error); + +INDEXSTORE_PUBLIC void +indexstore_record_reader_dispose(indexstore_record_reader_t); + +#if INDEXSTORE_HAS_BLOCKS +/// Goes through the symbol data and passes symbols to \c receiver, for the +/// symbol data that \c filter returns true on. +/// +/// This allows allocating memory only for the record symbols that the caller is +/// interested in. +INDEXSTORE_PUBLIC bool +indexstore_record_reader_search_symbols(indexstore_record_reader_t, + INDEXSTORE_NOESCAPE bool(^filter)(indexstore_symbol_t symbol, bool *stop), + INDEXSTORE_NOESCAPE void(^receiver)(indexstore_symbol_t symbol)); + +/// \param nocache if true, avoids allocating memory for the symbols. +/// Useful when the caller does not intend to keep \c indexstore_record_reader_t +/// for more queries. +INDEXSTORE_PUBLIC bool +indexstore_record_reader_symbols_apply(indexstore_record_reader_t, + bool nocache, + INDEXSTORE_NOESCAPE bool(^applier)(indexstore_symbol_t symbol)); + +INDEXSTORE_PUBLIC bool +indexstore_record_reader_occurrences_apply(indexstore_record_reader_t, + INDEXSTORE_NOESCAPE bool(^applier)(indexstore_occurrence_t occur)); + +INDEXSTORE_PUBLIC bool +indexstore_record_reader_occurrences_in_line_range_apply(indexstore_record_reader_t, + unsigned line_start, + unsigned line_count, + INDEXSTORE_NOESCAPE bool(^applier)(indexstore_occurrence_t occur)); + +/// \param symbols if non-zero \c symbols_count, indicates the list of symbols +/// that we want to get occurrences for. An empty array indicates that we want +/// occurrences for all symbols. +/// \param related_symbols Same as \c symbols but for related symbols. +INDEXSTORE_PUBLIC bool +indexstore_record_reader_occurrences_of_symbols_apply(indexstore_record_reader_t, + indexstore_symbol_t *symbols, size_t symbols_count, + indexstore_symbol_t *related_symbols, size_t related_symbols_count, + INDEXSTORE_NOESCAPE bool(^applier)(indexstore_occurrence_t occur)); +#endif + +INDEXSTORE_PUBLIC bool +indexstore_record_reader_search_symbols_f(indexstore_record_reader_t, + void *filter_ctx, + INDEXSTORE_NOESCAPE bool(*filter)(void *filter_ctx, indexstore_symbol_t symbol, bool *stop), + void *receiver_ctx, + INDEXSTORE_NOESCAPE void(*receiver)(void *receiver_ctx, indexstore_symbol_t symbol)); + +INDEXSTORE_PUBLIC bool +indexstore_record_reader_symbols_apply_f(indexstore_record_reader_t, + bool nocache, + void *context, + INDEXSTORE_NOESCAPE bool(*applier)(void *context, indexstore_symbol_t symbol)); + +INDEXSTORE_PUBLIC bool +indexstore_record_reader_occurrences_apply_f(indexstore_record_reader_t, + void *context, + INDEXSTORE_NOESCAPE bool(*applier)(void *context, indexstore_occurrence_t occur)); + +INDEXSTORE_PUBLIC bool +indexstore_record_reader_occurrences_in_line_range_apply_f(indexstore_record_reader_t, + unsigned line_start, + unsigned line_count, + void *context, + INDEXSTORE_NOESCAPE bool(*applier)(void *context, indexstore_occurrence_t occur)); + +INDEXSTORE_PUBLIC bool +indexstore_record_reader_occurrences_of_symbols_apply_f(indexstore_record_reader_t, + indexstore_symbol_t *symbols, size_t symbols_count, + indexstore_symbol_t *related_symbols, size_t related_symbols_count, + void *context, + INDEXSTORE_NOESCAPE bool(*applier)(void *context, indexstore_occurrence_t occur)); + +typedef void *indexstore_unit_reader_t; + +INDEXSTORE_PUBLIC indexstore_unit_reader_t +indexstore_unit_reader_create(indexstore_t store, const char *unit_name, + indexstore_error_t *error); + +INDEXSTORE_PUBLIC void +indexstore_unit_reader_dispose(indexstore_unit_reader_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_reader_get_provider_identifier(indexstore_unit_reader_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_reader_get_provider_version(indexstore_unit_reader_t); + +INDEXSTORE_PUBLIC void +indexstore_unit_reader_get_modification_time(indexstore_unit_reader_t, + int64_t *seconds, + int64_t *nanoseconds); + +INDEXSTORE_PUBLIC bool +indexstore_unit_reader_is_system_unit(indexstore_unit_reader_t); + +INDEXSTORE_PUBLIC bool +indexstore_unit_reader_is_module_unit(indexstore_unit_reader_t); + +INDEXSTORE_PUBLIC bool +indexstore_unit_reader_is_debug_compilation(indexstore_unit_reader_t); + +INDEXSTORE_PUBLIC bool +indexstore_unit_reader_has_main_file(indexstore_unit_reader_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_reader_get_main_file(indexstore_unit_reader_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_reader_get_module_name(indexstore_unit_reader_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_reader_get_working_dir(indexstore_unit_reader_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_reader_get_output_file(indexstore_unit_reader_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_reader_get_sysroot_path(indexstore_unit_reader_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_reader_get_target(indexstore_unit_reader_t); + +typedef void *indexstore_unit_dependency_t; +typedef void *indexstore_unit_include_t; + +typedef enum { + INDEXSTORE_UNIT_DEPENDENCY_UNIT = 1, + INDEXSTORE_UNIT_DEPENDENCY_RECORD = 2, + INDEXSTORE_UNIT_DEPENDENCY_FILE = 3, +} indexstore_unit_dependency_kind_t; + +INDEXSTORE_PUBLIC indexstore_unit_dependency_kind_t +indexstore_unit_dependency_get_kind(indexstore_unit_dependency_t); + +INDEXSTORE_PUBLIC bool +indexstore_unit_dependency_is_system(indexstore_unit_dependency_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_dependency_get_filepath(indexstore_unit_dependency_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_dependency_get_modulename(indexstore_unit_dependency_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_dependency_get_name(indexstore_unit_dependency_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_include_get_source_path(indexstore_unit_include_t); + +INDEXSTORE_PUBLIC indexstore_string_ref_t +indexstore_unit_include_get_target_path(indexstore_unit_include_t); + +INDEXSTORE_PUBLIC unsigned +indexstore_unit_include_get_source_line(indexstore_unit_include_t); + +#if INDEXSTORE_HAS_BLOCKS +INDEXSTORE_PUBLIC bool +indexstore_unit_reader_dependencies_apply(indexstore_unit_reader_t, + INDEXSTORE_NOESCAPE bool(^applier)(indexstore_unit_dependency_t)); + +INDEXSTORE_PUBLIC bool +indexstore_unit_reader_includes_apply(indexstore_unit_reader_t, + INDEXSTORE_NOESCAPE bool(^applier)(indexstore_unit_include_t)); +#endif + +INDEXSTORE_PUBLIC bool +indexstore_unit_reader_dependencies_apply_f(indexstore_unit_reader_t, + void *context, + INDEXSTORE_NOESCAPE bool(*applier)(void *context, indexstore_unit_dependency_t)); + +INDEXSTORE_PUBLIC bool +indexstore_unit_reader_includes_apply_f(indexstore_unit_reader_t, + void *context, + INDEXSTORE_NOESCAPE bool(*applier)(void *context, indexstore_unit_include_t)); + +INDEXSTORE_END_DECLS + +#endif Index: clang/lib/Index/BitstreamUtil.h =================================================================== --- /dev/null +++ clang/lib/Index/BitstreamUtil.h @@ -0,0 +1,33 @@ +//===--- IndexDataStoreUtils.h - Functions/constants for the data store ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_INDEX_BITSTREAMUTIL_H +#define LLVM_CLANG_LIB_INDEX_BITSTREAMUTIL_H + +#include "llvm/ADT/SmallVector.h" + +namespace llvm { + class BitstreamWriter; +} + +namespace clang { +namespace index { +namespace store { + +void emitBlockID(unsigned ID, const char *Name, + llvm::BitstreamWriter &Stream, llvm::SmallVectorImpl &Record); + +void emitRecordID(unsigned ID, const char *Name, + llvm::BitstreamWriter &Stream, llvm::SmallVectorImpl &Record); + +} // end namespace store +} // end namespace index +} // end namespace clang + +#endif Index: clang/lib/Index/BitstreamUtil.cpp =================================================================== --- /dev/null +++ clang/lib/Index/BitstreamUtil.cpp @@ -0,0 +1,49 @@ +//===--- IndexDataStoreUtils.cpp - Functions/constants for the data store -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "BitstreamUtil.h" + +#include "llvm/Bitstream/BitstreamWriter.h" +#include "llvm/Bitstream/BitCodes.h" + +using namespace clang; +using namespace llvm; + +namespace clang { +namespace index { +namespace store { + +void emitBlockID(unsigned ID, const char *Name, + llvm::BitstreamWriter &Stream, llvm::SmallVectorImpl &Record) { + Record.clear(); + Record.push_back(ID); + Stream.EmitRecord(bitc::BLOCKINFO_CODE_SETBID, Record); + + // Emit the block name if present. + if (!Name || Name[0] == 0) + return; + Record.clear(); + while (*Name) + Record.push_back(*Name++); + Stream.EmitRecord(bitc::BLOCKINFO_CODE_BLOCKNAME, Record); +} + +void emitRecordID(unsigned ID, const char *Name, + llvm::BitstreamWriter &Stream, + llvm::SmallVectorImpl &Record) { + Record.clear(); + Record.push_back(ID); + while (*Name) + Record.push_back(*Name++); + Stream.EmitRecord(bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); +} + +} // end namespace store +} // end namespace index +} // end namespace clang Index: clang/lib/Index/CMakeLists.txt =================================================================== --- clang/lib/Index/CMakeLists.txt +++ clang/lib/Index/CMakeLists.txt @@ -4,19 +4,26 @@ ) add_clang_library(clangIndex + BitstreamUtil.cpp CodegenNameGenerator.cpp CommentToXML.cpp - FileIndexRecord.cpp + DeclOccurrenceCollector.cpp + EmitIndexAction.cpp + GenerateIndexAction.cpp + IndexAction.cpp IndexBody.cpp IndexDecl.cpp IndexingAction.cpp IndexingContext.cpp + IndexOptions.cpp + IndexRecordWriter.cpp IndexSymbol.cpp IndexTypeSourceInfo.cpp + IndexUnitWriter.cpp USRGeneration.cpp + PathStorage.cpp ADDITIONAL_HEADERS - IndexingContext.h SimpleFormatContext.h LINK_LIBS Index: clang/lib/Index/CodegenNameGenerator.cpp =================================================================== --- clang/lib/Index/CodegenNameGenerator.cpp +++ clang/lib/Index/CodegenNameGenerator.cpp @@ -12,12 +12,203 @@ #include "clang/Index/CodegenNameGenerator.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Mangle.h" +#include "clang/AST/VTableBuilder.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace clang::index; +struct CodegenNameGenerator::Implementation { + std::unique_ptr MC; + llvm::DataLayout DL; + + Implementation(ASTContext &Ctx) + : MC(Ctx.createMangleContext()), + DL(Ctx.getTargetInfo().getDataLayout()) {} + + bool writeName(const Decl *D, raw_ostream &OS) { + // First apply frontend mangling. + SmallString<128> FrontendBuf; + llvm::raw_svector_ostream FrontendBufOS(FrontendBuf); + if (auto *FD = dyn_cast(D)) { + if (FD->isDependentContext()) + return true; + if (writeFuncOrVarName(FD, FrontendBufOS)) + return true; + } else if (auto *VD = dyn_cast(D)) { + if (writeFuncOrVarName(VD, FrontendBufOS)) + return true; + } else if (auto *MD = dyn_cast(D)) { + MC->mangleObjCMethodNameWithoutSize(MD, OS); + return false; + } else if (auto *ID = dyn_cast(D)) { + writeObjCClassName(ID, FrontendBufOS); + } else { + return true; + } + + // Now apply backend mangling. + llvm::Mangler::getNameWithPrefix(OS, FrontendBufOS.str(), DL); + return false; + } + + std::string getName(const Decl *D) { + std::string Name; + { + llvm::raw_string_ostream OS(Name); + writeName(D, OS); + } + return Name; + } + + enum ObjCKind { + ObjCClass, + ObjCMetaclass, + }; + + std::vector getAllManglings(const ObjCContainerDecl *OCD) { + StringRef ClassName; + if (const auto *OID = dyn_cast(OCD)) + ClassName = OID->getObjCRuntimeNameAsString(); + else if (const auto *OID = dyn_cast(OCD)) + ClassName = OID->getObjCRuntimeNameAsString(); + + if (ClassName.empty()) + return {}; + + auto Mangle = [&](ObjCKind Kind, StringRef ClassName) -> std::string { + SmallString<40> Mangled; + auto Prefix = getClassSymbolPrefix(Kind, OCD->getASTContext()); + llvm::Mangler::getNameWithPrefix(Mangled, Prefix + ClassName, DL); + return Mangled.str(); + }; + + return { + Mangle(ObjCClass, ClassName), + Mangle(ObjCMetaclass, ClassName), + }; + } + + std::vector getAllManglings(const Decl *D) { + if (const auto *OCD = dyn_cast(D)) + return getAllManglings(OCD); + + if (!(isa(D) || isa(D))) + return {}; + + const NamedDecl *ND = cast(D); + + ASTContext &Ctx = ND->getASTContext(); + std::unique_ptr M(Ctx.createMangleContext()); + + std::vector Manglings; + + auto hasDefaultCXXMethodCC = [](ASTContext &C, const CXXMethodDecl *MD) { + auto DefaultCC = C.getDefaultCallingConvention(/*IsVariadic=*/false, + /*IsCSSMethod=*/true); + auto CC = MD->getType()->getAs()->getCallConv(); + return CC == DefaultCC; + }; + + if (const auto *CD = dyn_cast_or_null(ND)) { + Manglings.emplace_back(getMangledStructor(CD, Ctor_Base)); + + if (Ctx.getTargetInfo().getCXXABI().isItaniumFamily()) + if (!CD->getParent()->isAbstract()) + Manglings.emplace_back(getMangledStructor(CD, Ctor_Complete)); + + if (Ctx.getTargetInfo().getCXXABI().isMicrosoft()) + if (CD->hasAttr() && CD->isDefaultConstructor()) + if (!(hasDefaultCXXMethodCC(Ctx, CD) && CD->getNumParams() == 0)) + Manglings.emplace_back(getMangledStructor(CD, Ctor_DefaultClosure)); + } else if (const auto *DD = dyn_cast_or_null(ND)) { + Manglings.emplace_back(getMangledStructor(DD, Dtor_Base)); + if (Ctx.getTargetInfo().getCXXABI().isItaniumFamily()) { + Manglings.emplace_back(getMangledStructor(DD, Dtor_Complete)); + if (DD->isVirtual()) + Manglings.emplace_back(getMangledStructor(DD, Dtor_Deleting)); + } + } else if (const auto *MD = dyn_cast_or_null(ND)) { + Manglings.emplace_back(getName(ND)); + if (MD->isVirtual()) + if (const auto *TIV = Ctx.getVTableContext()->getThunkInfo(MD)) + for (const auto &T : *TIV) + Manglings.emplace_back(getMangledThunk(MD, T)); + } + + return Manglings; + } + +private: + bool writeFuncOrVarName(const NamedDecl *D, raw_ostream &OS) { + if (MC->shouldMangleDeclName(D)) { + if (const auto *CtorD = dyn_cast(D)) + MC->mangleCXXCtor(CtorD, Ctor_Complete, OS); + else if (const auto *DtorD = dyn_cast(D)) + MC->mangleCXXDtor(DtorD, Dtor_Complete, OS); + else + MC->mangleName(D, OS); + return false; + } else { + IdentifierInfo *II = D->getIdentifier(); + if (!II) + return true; + OS << II->getName(); + return false; + } + } + + void writeObjCClassName(const ObjCInterfaceDecl *D, raw_ostream &OS) { + OS << getClassSymbolPrefix(ObjCClass, D->getASTContext()); + OS << D->getObjCRuntimeNameAsString(); + } + + static StringRef getClassSymbolPrefix(ObjCKind Kind, const ASTContext &Context) { + if (Context.getLangOpts().ObjCRuntime.isGNUFamily()) + return Kind == ObjCMetaclass ? "_OBJC_METACLASS_" : "_OBJC_CLASS_"; + return Kind == ObjCMetaclass ? "OBJC_METACLASS_$_" : "OBJC_CLASS_$_"; + } + + std::string getMangledStructor(const NamedDecl *ND, unsigned StructorType) { + std::string FrontendBuf; + llvm::raw_string_ostream FOS(FrontendBuf); + + if (const auto *CD = dyn_cast_or_null(ND)) + MC->mangleCXXCtor(CD, static_cast(StructorType), FOS); + else if (const auto *DD = dyn_cast_or_null(ND)) + MC->mangleCXXDtor(DD, static_cast(StructorType), FOS); + + std::string BackendBuf; + llvm::raw_string_ostream BOS(BackendBuf); + + llvm::Mangler::getNameWithPrefix(BOS, FOS.str(), DL); + + return BOS.str(); + } + + std::string getMangledThunk(const CXXMethodDecl *MD, const ThunkInfo &T) { + std::string FrontendBuf; + llvm::raw_string_ostream FOS(FrontendBuf); + + MC->mangleThunk(MD, T, FOS); + + std::string BackendBuf; + llvm::raw_string_ostream BOS(BackendBuf); + + llvm::Mangler::getNameWithPrefix(BOS, FOS.str(), DL); + + return BOS.str(); + } +}; + CodegenNameGenerator::CodegenNameGenerator(ASTContext &Ctx) - : Impl(new ASTNameGenerator(Ctx)) { + : Impl(new Implementation(Ctx)) { } CodegenNameGenerator::~CodegenNameGenerator() { Index: clang/lib/Index/DeclOccurrenceCollector.cpp =================================================================== --- /dev/null +++ clang/lib/Index/DeclOccurrenceCollector.cpp @@ -0,0 +1,41 @@ +//===- IndexingAction.cpp - Frontend index action -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/DeclOccurrenceCollector.h" + +namespace clang { +namespace index { + +bool DeclOccurrenceCollector::handleDeclOccurence(const Decl *D, SymbolRoleSet Roles, + ArrayRef Relations, + SourceLocation Loc, ASTNodeInfo ASTNode) { + Loc = SM.getFileLoc(Loc); + if (Loc.isInvalid()) + return true; + + FileID FID; + unsigned Offset; + std::tie(FID, Offset) = SM.getDecomposedLoc(Loc); + + if (FID.isInvalid()) + return true; + + // Ignore the predefines buffer. + const FileEntry *FE = SM.getFileEntryForID(FID); + if (!FE) + return true; + + IndexRecordWriter &Rec = RecordByFile.insert( + {FID, IndexRecordWriter(IndexCtx->isSystemFile(FID)) } + ).first->second; + Rec.addDeclOccurence(Roles, FID, Offset, D, Relations); + return true; +} + +} // namespace index +} // namespace clang \ No newline at end of file Index: clang/lib/Index/EmitIndexAction.cpp =================================================================== --- /dev/null +++ clang/lib/Index/EmitIndexAction.cpp @@ -0,0 +1,522 @@ +//===- IndexingAction.cpp - Frontend index action -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/EmitIndexAction.h" + +#include "clang/Index/IndexDataFormat.h" +#include "IndexPPCallbacks.h" +#include "clang/Basic/Version.h" +#include "clang/Basic/DiagnosticFrontend.h" +#include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Serialization/ASTReader.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/Support/Errc.h" + +namespace clang { +namespace index { + +using namespace llvm; + +static Module * getModBeingCompiled(const CompilerInstance &CI) { + return CI.getLangOpts().isCompilingModule() + ? CI.getPreprocessor().getHeaderSearchInfo().lookupModule(CI.getLangOpts().CurrentModule, /*AllowSearch=*/false) + : nullptr; +} + +static std::string getOutputFile(const CompilerInstance &CI) { + std::string Result = CI.getFrontendOpts().OutputFile; + return + !Result.empty() + ? Result + : CI.getFrontendOpts().Inputs[0].getFile().str() + ".o"; +} + +static const FileEntry * getMainFile(const CompilerInstance &CI) { + if (CI.getLangOpts().isCompilingModule() || + CI.getFrontendOpts().ProgramAction == frontend::GeneratePCH) + return nullptr; + + SourceManager &SM = CI.getSourceManager(); + return SM.getFileEntryForID(SM.getMainFileID()); +} + +class IncludePPCallbacks : public PPCallbacks { + IndexingContext &IndexCtx; + RecordingOptions RecordOpts; + IndexUnitWriter &UnitWriter; + SourceManager &SourceMgr; + +public: + IncludePPCallbacks(IndexingContext &indexCtx, RecordingOptions recordOpts, + IndexUnitWriter &UnitWriter, + SourceManager &SourceMgr) + : IndexCtx(indexCtx), RecordOpts(recordOpts), UnitWriter(UnitWriter), + SourceMgr(SourceMgr) {} + +private: + virtual void InclusionDirective( + SourceLocation InclusionDirectiveLoc, + const Token &, + StringRef, + bool, + CharSourceRange, + const FileEntry *IncludedFile, + StringRef, + StringRef, + const Module *ImportedModule, + SrcMgr::CharacteristicKind FileType + ) override { + // We don't want to treat imports as includes. + if (ImportedModule) + return; + + if (RecordOpts.RecordIncludes == RecordingOptions::IncludesRecordingKind::None) + return; + + if (!InclusionDirectiveLoc.isFileID() || !IncludedFile || !IncludedFile->isValid()) + return; + + std::pair InclusionDirectiveDecLoc = + SourceMgr.getDecomposedExpansionLoc(InclusionDirectiveLoc); + + if (RecordOpts.RecordIncludes == RecordingOptions::IncludesRecordingKind::UserOnly && IndexCtx.isSystemFile(InclusionDirectiveDecLoc.first)) + return; // Ignore includes of system headers. + + auto *FE = SourceMgr.getFileEntryForID(InclusionDirectiveDecLoc.first); + if (!FE) + return; + + UnitWriter.addIncludedFile( + FE, + SourceMgr.getLineNumber(InclusionDirectiveDecLoc.first, InclusionDirectiveDecLoc.second), + IncludedFile + ); + } +}; + +SourceFilesDependencyCollector::SourceFilesDependencyCollector( + const CompilerInstance &CI, + IndexingContext &indexCtx, + RecordingOptions recordOpts +) : + CI(CI), IndexCtx(indexCtx), RecordOpts(recordOpts), + UnitWriter( + makeIndexUnitWriter( + CI, + RecordOpts, + getOutputFile(CI), + getMainFile(CI), + getModBeingCompiled(CI) + ) + ) +{ } + +void SourceFilesDependencyCollector::attachToPreprocessor(Preprocessor &PP) { + DependencyCollector::attachToPreprocessor(PP); + PP.addPPCallbacks(llvm::make_unique( + IndexCtx, RecordOpts, UnitWriter, PP.getSourceManager())); +} + +/// \returns either a Module that is both a submodule of UnitModule and owns the header \p FE. +static Module * findModuleForHeader(const CompilerInstance &CI, Module &UnitModule, const FileEntry &FE) { + if (auto Mod = CI.getPreprocessor().getHeaderSearchInfo().findModuleForHeader(&FE).getModule()) + if (Mod->isSubModuleOf(&UnitModule)) + return Mod; + return nullptr; +} + +bool SourceFilesDependencyCollector::sawDependency(StringRef Filename, bool FromModule, bool IsSystem, + bool IsModuleFile, bool IsMissing) { + bool sawIt = DependencyCollector::sawDependency( + Filename, FromModule, IsSystem, IsModuleFile, IsMissing); + if (sawIt) { + if (auto *FE = CI.getSourceManager().getFileManager().getFile(Filename)) { + assert(FE); + + Module * ModForHead = nullptr; + { + Module * Mod = getModBeingCompiled(CI); + if (Mod) { + ModForHead = findModuleForHeader(CI, *Mod, *FE); + UnitWriter.addModule(ModForHead); + } + } + + UnitWriter.addSourceFile( + FE, + IsSystem || isInSysroot(Filename), + ModForHead + ); + } + } + return sawIt; +} + +bool SourceFilesDependencyCollector::isInSysroot(StringRef Filename) { + const auto& Sysroot = CI.getHeaderSearchOpts().Sysroot; + // FIXME: Make this portable. + return !Sysroot.empty() && (Sysroot != "/") && Filename.startswith(Sysroot); +} + +ActionContext::ActionContext(const IndexingOptions& IndexOpts, const CompilerInstance &CI, const RecordingOptions& RecordOpts) +: CI(CI), + DeclsDataCollector( + CI.getSourceManager() + ), + Ctx(IndexOpts, DeclsDataCollector), + DepCollector(CI, Ctx, RecordOpts), + RecordOpts(RecordOpts), + IndexOpts(IndexOpts) +{ + DepCollector.attachToPreprocessor(CI.getPreprocessor()); + DeclsDataCollector.setIndexingContext(Ctx); +} + +// FIXME: Some better implementation. +template +static void reportError(const CompilerInstance &CI, const char (&Format)[N], const std::string& Param1 = "", const std::string& Param2 = "") { + DiagnosticsEngine &Diag = CI.getDiagnostics(); + unsigned DiagID = Diag.getCustomDiagID( + DiagnosticsEngine::Error, Format); + if (!Param2.empty()) + Diag.Report(DiagID) << Param1 << Param2; + else + Diag.Report(DiagID) << Param1; +}; + +/// Writes records in \p RecordByFile to disk and adds them as dependencies to \p UnitModule. +void writeIndexRecordsToDisk( + const llvm::DenseMap& RecordByFile, + IndexUnitWriter &UnitWriter, + const CompilerInstance &CI, + const RecordingOptions& RecordOpts, + const Module *UnitModule +) { + auto& ASTCtx = CI.getASTContext(); + PrintingPolicy Policy(ASTCtx.getLangOpts()); + Policy.SuppressTemplateArgsInCXXConstructors = true; + + std::shared_ptr CGNameGen; + if (RecordOpts.RecordSymbolCodeGenName) + CGNameGen = std::make_shared(ASTCtx); + + for (const auto& It : RecordByFile) { + const FileID FID = It.first; + const IndexRecordWriter &Rec = It.second; + const FileEntry *FE = CI.getSourceManager().getFileEntryForID(FID); + assert(FE); + + if (Rec.isEmpty()) + continue; + + llvm::Optional RecordFilename = Rec.writeToDisk(FE->getName(), RecordOpts, Policy, CGNameGen, CI.getDiagnostics()); + if (!RecordFilename) { + reportError(CI, "failed to write record file for source file '%0' to disk", FE->getName(), ""); + return; + } + + Module * Mod = nullptr; + if (UnitModule) { + if (auto ModCandidate = CI.getPreprocessor().getHeaderSearchInfo().findModuleForHeader(FE).getModule()) { + if (ModCandidate->isSubModuleOf(UnitModule)) { + Mod = ModCandidate; + UnitWriter.addModule(Mod); + } + } + } + + UnitWriter.addIndexRecord( + RecordFilename.getValue(), + FE, Rec.isSystem(), + Mod + ); + } +} + +void ActionContext::emitCollectedData() { + // FIXME: FrontendAction::EndSourceFile() should probably not call + // CI.getDiagnosticClient().EndSourceFile()' until after it has called + // 'EndSourceFileAction()', so that code executing during + // EndSourceFileAction() can emit diagnostics. If this is fixed, + // DiagClientBeginEndRAII can go away. + CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts()); + auto DiagnosticClientEndSourceFile = llvm::make_scope_exit( + [this](){ + CI.getDiagnosticClient().EndSourceFile(); + } + ); + + std::string Error; + if (initIndexDirectory(RecordOpts, Error)) { + reportError(CI, "failed creating index directory %0", Error); + return; + } + + IndexUnitWriter& UnitWriter = DepCollector.UnitWriter; + + const Module * UnitModule = getModBeingCompiled(CI); + std::string ModuleName = + UnitModule ? UnitModule->getFullModuleName() : std::string(); + + + if (auto Reader = CI.getModuleManager()) { + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); + Reader->getModuleManager().visit( + [&](serialization::ModuleFile &Mod) -> bool { + Module *UnitMod = HS.lookupModule(Mod.ModuleName, /*AllowSearch=*/false); + const bool isSystemMod = + Mod.isModule() + && UnitMod && UnitMod->IsSystem; + + if (!isSystemMod || RecordOpts.RecordSystemDependencies) { + SmallString<256> AbsPath(Mod.File->getName()); + CI.getFileManager().makeAbsolutePath(AbsPath); + UnitWriter.addIndexUnit(Mod.File, AbsPath, isSystemMod, UnitMod); + if (Mod.isModule()) { + llvm::Optional IndexUnitExist = doesIndexUnitForModuleExist( + Mod.FileName, + CI.getFileManager(), + RecordOpts); + + if (!IndexUnitExist.hasValue()) + reportError(CI, "failed to stat index unit for module %0", AbsPath.str()); + + if (!IndexUnitExist.getValue()) + emitIndexDataForModuleFile(Mod, CI, IndexOpts, RecordOpts); + } + } + return true; // skip module dependencies. + } + ); + } + + if (std::error_code EC = sys::fs::create_directory(RecordOpts.RecordDir)) { + reportError(CI, "failed to create directory '%0': %1", RecordOpts.RecordDir, EC.message()); + return; + } + writeIndexRecordsToDisk(DeclsDataCollector.getRecordByFile(), UnitWriter, CI, RecordOpts, UnitModule); + + { + std::string Error; + if (UnitWriter.writeToDisk(Error)) { + reportError(CI, "failed writing unit data: %0", Error); + return; + } + } +} + + +class IndexRecordingASTConsumer : public ASTConsumer { + std::shared_ptr Context; + +public: + IndexRecordingASTConsumer(std::shared_ptr Context) + : Context(Context) {} + +protected: + void Initialize(ASTContext &ASTContextInst) override { + Context->Ctx.setASTContext(ASTContextInst); + Context->DeclsDataCollector.initialize(ASTContextInst); + } + + bool HandleTopLevelDecl(DeclGroupRef DG) override { + return Context->Ctx.indexDeclGroupRef(DG); + } + + void HandleInterestingDecl(DeclGroupRef DG) override { + // Ignore deserialized decls. + } + + void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override { + Context->Ctx.indexDeclGroupRef(DG); + } + + void HandleTranslationUnit(ASTContext &Ctx) override {} +}; + +EmitIndexAction::EmitIndexAction(const IndexingOptions& IndexOpts, + const RecordingOptions& RecordOpts) + : RecordOpts(RecordOpts), + IndexOpts(IndexOpts) {} + +std::unique_ptr EmitIndexAction::CreateASTConsumer(CompilerInstance &CI, + StringRef) { + Context = std::make_shared(IndexOpts, CI, RecordOpts); + return llvm::make_unique(Context); +} + +void EmitIndexAction::EndSourceFileAction() { + if (Context) + Context->emitCollectedData(); +} + +void emitIndexDataForModuleFile(serialization::ModuleFile &Mod, + const CompilerInstance &CI, const IndexingOptions& IndexOpts, + const RecordingOptions& RecordOpts) { + // FIXME: FrontendAction::EndSourceFile() should probably not call + // CI.getDiagnosticClient().EndSourceFile()' until after it has called + // 'EndSourceFileAction()', so that code executing during + // EndSourceFileAction() can emit diagnostics. If this is fixed, + // DiagClientBeginEndRAII can go away. + CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts()); + auto DiagnosticClientEndSourceFile = llvm::make_scope_exit( + [&CI](){ + CI.getDiagnosticClient().EndSourceFile(); + } + ); + + DiagnosticsEngine &Diag = CI.getDiagnostics(); + Diag.Report(Mod.ImportLoc, diag::remark_index_producing_module_file_data) + << Mod.FileName; + + Module *UnitModule = CI.getPreprocessor().getHeaderSearchInfo().lookupModule(Mod.ModuleName, /*AllowSearch=*/false); + + DeclOccurrenceCollector DeclsDataCollector( CI.getSourceManager() ); + { + IndexingContext IndexCtx(IndexOpts, DeclsDataCollector); + DeclsDataCollector.setIndexingContext(IndexCtx); + + IndexCtx.setASTContext(CI.getASTContext()); + + for (const Decl *D : CI.getModuleManager()->getModuleFileLevelDecls(Mod)) { + IndexCtx.indexTopLevelDecl(D); + } + DeclsDataCollector.finish(); + } + + { + std::string Error; + if (initIndexDirectory(RecordOpts, Error)) { + reportError(CI, "failed creating index directory %0", Error); + return; + } + } + + HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); + + SmallString<128> WorkDir; + if (!CI.getFileManager().getFileSystemOpts().WorkingDir.empty()) { + WorkDir = CI.getFileManager().getFileSystemOpts().WorkingDir; + if (!llvm::sys::path::is_absolute(WorkDir)) { + llvm::sys::fs::make_absolute(WorkDir); + } + } else { + std::error_code EC = llvm::sys::fs::current_path(WorkDir); + if (EC) { + reportError(CI, "failed to determine current working directory"); + } + } + + IndexUnitWriter UnitWriter = makeIndexUnitWriter(CI, RecordOpts, Mod.FileName, nullptr, UnitModule); + + if (UnitModule) { + serialization::ModuleFile *ModFile = CI.getModuleManager()->getModuleManager().lookup(UnitModule->getASTFile()); + assert(ModFile && "no module file loaded for module ?"); + + for (auto *Mod : ModFile->Imports) { + auto *UnitMod = HS.lookupModule(Mod->ModuleName, /*AllowSearch=*/false); + if (!UnitMod->IsSystem || RecordOpts.RecordSystemDependencies) { + SmallString<256> AbsPath(Mod->File->getName()); + CI.getFileManager().makeAbsolutePath(AbsPath); + UnitWriter.addIndexUnit(Mod->File, AbsPath, UnitMod->IsSystem, UnitMod); + } + } + + CI.getModuleManager()->visitInputFiles( + *ModFile, RecordOpts.RecordSystemDependencies, + /*Complain=*/false, + [&](const serialization::InputFile &IF, bool isSystemFile) { + auto *FE = IF.getFile(); + if (!FE) + return; + // Ignore module map files, they are not as important to track as + // source files and they may be auto-generated which would create an + // undesirable dependency on an intermediate build byproduct. + if (FE->getName().endswith("module.modulemap")) + return; + + // Try to find a Module that is both a submodule of UnitModule and owns the header. + Module * ModForHead = nullptr; + if (auto Mod = CI.getPreprocessor().getHeaderSearchInfo().findModuleForHeader(FE).getModule()) + if (Mod->isSubModuleOf(UnitModule)) + ModForHead = Mod; + + UnitWriter.addModule(ModForHead); + + UnitWriter.addSourceFile( + FE, + isSystemFile, + ModForHead + ); + } + ); + } + + if (std::error_code EC = sys::fs::create_directory(RecordOpts.RecordDir)) { + reportError(CI, "failed to create directory '%0': %1", RecordOpts.RecordDir, EC.message()); + return; + } + writeIndexRecordsToDisk(DeclsDataCollector.getRecordByFile(), UnitWriter, CI, RecordOpts, UnitModule); + + std::string Error; + if (UnitWriter.writeToDisk(Error)) { + reportError(CI, "failed writing unit data: %0", Error); + return; + } + + if (UnitModule) { + serialization::ModuleFile *ModFile = CI.getModuleManager()->getModuleManager().lookup(UnitModule->getASTFile()); + for (auto *Mod : ModFile->Imports) { + auto *UnitMod = HS.lookupModule(Mod->ModuleName, /*AllowSearch=*/false); + + if (!UnitMod->IsSystem || RecordOpts.RecordSystemDependencies) { + if (Mod->isModule()) { + llvm::Optional IndexUnitExist = doesIndexUnitForModuleExist( + Mod->FileName, + CI.getFileManager(), + RecordOpts); + if (IndexUnitExist.hasValue() && !IndexUnitExist.getValue()) + emitIndexDataForModuleFile(*Mod, CI, IndexOpts, RecordOpts); + } + } + } + } +} + +bool emitIndexDataForModule(const Module *Mod, + const CompilerInstance &CI) { + assert(Mod); + auto astReader = CI.getModuleManager(); + serialization::ModuleFile *ModFile = + astReader->getModuleManager().lookup(Mod->getASTFile()); + assert(ModFile && "no module file loaded for module ?"); + + const RecordingOptions RecOpts = parseIndexEmittingOptions(CI.getFrontendOpts()); + + llvm::Optional IndexUnitExist = doesIndexUnitForModuleExist( + ModFile->FileName, + CI.getFileManager(), + RecOpts + ); + if (IndexUnitExist.hasValue() && IndexUnitExist.getValue()) + return false; + + emitIndexDataForModuleFile( + *ModFile, + CI, + parseIndexGenerationOptions(CI.getFrontendOpts()), + RecOpts + ); + return true; +} + + +} // namespace index +} // namespace clang \ No newline at end of file Index: clang/lib/Index/FSUtil.h =================================================================== --- /dev/null +++ clang/lib/Index/FSUtil.h @@ -0,0 +1,66 @@ +//===--- FSUtil.h - File system utilities ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_FSUTIL_H +#define LLVM_CLANG_INDEX_FSUTIL_H + +#include "clang/Index/IndexRecordWriter.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + + + +namespace clang { +namespace index { + +using namespace llvm; + +/// Creates a unique file with name according to the given \p TempPathModel, writes content of \p Buffer to the file and renames it to \p FinalPath. +/// \returns false when the file was successfully created, true otherwise. +inline bool atomicFileWrite( + StringRef TempPathModel, + StringRef FinalPath, + const SmallString<512>& Buffer, std::string &Error +) { + SmallString<128> GeneratedUniqPath; + int TempFD; + if (sys::fs::createUniqueFile(TempPathModel.str(), TempFD, GeneratedUniqPath)) { + raw_string_ostream Err(Error); + Err << "failed to create temporary file: " << TempPathModel; + return true; + } + + raw_fd_ostream OS(TempFD, /*shouldClose=*/true); + OS.write(Buffer.data(), Buffer.size()); + OS.close(); + TempFD = -1; + + if (OS.has_error()) { + raw_string_ostream Err(Error); + Err << "failed to write '" << GeneratedUniqPath << "': " << OS.error().message(); + OS.clear_error(); + return true; + } + + std::error_code EC = sys::fs::rename(/*from=*/GeneratedUniqPath.c_str(), /*to=*/FinalPath.str().c_str()); + if (EC) { + raw_string_ostream Err(Error); + Err << "failed to rename '" << GeneratedUniqPath << "' to '" << FinalPath << "': " << EC.message(); + return true; + } + + return false; +} + +} // end namespace index +} // end namespace clang + +#endif // LLVM_CLANG_INDEX_FSUTIL_H \ No newline at end of file Index: clang/lib/Index/FileIndexRecord.h =================================================================== --- clang/lib/Index/FileIndexRecord.h +++ /dev/null @@ -1,57 +0,0 @@ -//===--- FileIndexRecord.h - Index data per file ----------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_INDEX_FILEINDEXRECORD_H -#define LLVM_CLANG_LIB_INDEX_FILEINDEXRECORD_H - -#include "clang/Basic/SourceLocation.h" -#include "clang/Index/DeclOccurrence.h" -#include "clang/Index/IndexSymbol.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallVector.h" -#include - -namespace clang { -class IdentifierInfo; - -namespace index { - -/// Stores the declaration occurrences seen in a particular source or header -/// file of a translation unit -class FileIndexRecord { -private: - FileID FID; - bool IsSystem; - std::vector Decls; - -public: - FileIndexRecord(FileID FID, bool IsSystem) : FID(FID), IsSystem(IsSystem) {} - - ArrayRef getDeclOccurrencesSortedByOffset() const { - return Decls; - } - - FileID getFileID() const { return FID; } - bool isSystem() const { return IsSystem; } - - /// Adds an occurrence of the canonical declaration \c D at the supplied - /// \c Offset - /// - /// \param Roles the roles the occurrence fulfills in this position. - /// \param Offset the offset in the file of this occurrence. - /// \param D the canonical declaration this is an occurrence of. - /// \param Relations the set of symbols related to this occurrence. - void addDeclOccurence(SymbolRoleSet Roles, unsigned Offset, const Decl *D, - ArrayRef Relations); - void print(llvm::raw_ostream &OS) const; -}; - -} // end namespace index -} // end namespace clang - -#endif // LLVM_CLANG_LIB_INDEX_FILEINDEXRECORD_H Index: clang/lib/Index/FileIndexRecord.cpp =================================================================== --- clang/lib/Index/FileIndexRecord.cpp +++ /dev/null @@ -1,60 +0,0 @@ -//===--- FileIndexRecord.cpp - Index data per file --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "FileIndexRecord.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/DeclTemplate.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/Path.h" - -using namespace clang; -using namespace clang::index; - -void FileIndexRecord::addDeclOccurence(SymbolRoleSet Roles, unsigned Offset, - const Decl *D, - ArrayRef Relations) { - assert(D->isCanonicalDecl() && - "Occurrences should be associated with their canonical decl"); - - auto IsNextOccurence = [&]() -> bool { - if (Decls.empty()) - return true; - auto &Last = Decls.back(); - return Last.Offset < Offset; - }; - - if (IsNextOccurence()) { - Decls.emplace_back(Roles, Offset, D, Relations); - return; - } - - DeclOccurrence NewInfo(Roles, Offset, D, Relations); - // We keep Decls in order as we need to access them in this order in all cases. - auto It = llvm::upper_bound(Decls, NewInfo); - Decls.insert(It, std::move(NewInfo)); -} - -void FileIndexRecord::print(llvm::raw_ostream &OS) const { - OS << "DECLS BEGIN ---\n"; - for (auto &DclInfo : Decls) { - const Decl *D = DclInfo.Dcl; - SourceManager &SM = D->getASTContext().getSourceManager(); - SourceLocation Loc = SM.getFileLoc(D->getLocation()); - PresumedLoc PLoc = SM.getPresumedLoc(Loc); - OS << llvm::sys::path::filename(PLoc.getFilename()) << ':' << PLoc.getLine() - << ':' << PLoc.getColumn(); - - if (auto ND = dyn_cast(D)) { - OS << ' ' << ND->getNameAsString(); - } - - OS << '\n'; - } - OS << "DECLS END ---\n"; -} Index: clang/lib/Index/GenerateIndexAction.cpp =================================================================== --- /dev/null +++ clang/lib/Index/GenerateIndexAction.cpp @@ -0,0 +1,148 @@ +//===- GenerateIndexAction.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/GenerateIndexAction.h" + +#include "clang/Index/IndexDataFormat.h" +#include "IndexPPCallbacks.h" +#include "clang/Basic/Version.h" +#include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Serialization/ASTReader.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/Support/Errc.h" + +namespace clang { +namespace index { + + +static bool topLevelDeclVisitor(void *context, const Decl *D) { + IndexingContext &IndexCtx = *static_cast(context); + return IndexCtx.indexTopLevelDecl(D); +} + +static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IndexCtx) { + Unit.visitLocalTopLevelDecls(&IndexCtx, topLevelDeclVisitor); +} + +static void indexPreprocessorMacros(const Preprocessor &PP, + IndexDataConsumer &DataConsumer) { + for (const auto &M : PP.macros()) + if (MacroDirective *MD = M.second.getLatest()) + DataConsumer.handleMacroOccurence( + M.first, MD->getMacroInfo(), + static_cast(SymbolRole::Definition), + MD->getLocation()); +} + +void indexASTUnit(ASTUnit &Unit, IndexDataConsumer &DataConsumer, + const IndexingOptions& Opts) { + IndexingContext IndexCtx(Opts, DataConsumer); + IndexCtx.setASTContext(Unit.getASTContext()); + DataConsumer.initialize(Unit.getASTContext()); + DataConsumer.setPreprocessor(Unit.getPreprocessorPtr()); + + if (Opts.IndexMacrosInPreprocessor) + indexPreprocessorMacros(Unit.getPreprocessor(), DataConsumer); + indexTranslationUnit(Unit, IndexCtx); + DataConsumer.finish(); +} + +void indexTopLevelDecls(ASTContext &Ctx, Preprocessor &PP, + ArrayRef Decls, + IndexDataConsumer &DataConsumer, + const IndexingOptions& Opts) { + IndexingContext IndexCtx(Opts, DataConsumer); + IndexCtx.setASTContext(Ctx); + + DataConsumer.initialize(Ctx); + + if (Opts.IndexMacrosInPreprocessor) + indexPreprocessorMacros(PP, DataConsumer); + + for (const Decl *D : Decls) + IndexCtx.indexTopLevelDecl(D); + DataConsumer.finish(); +} + +std::unique_ptr +indexMacrosCallback(IndexDataConsumer &Consumer, const IndexingOptions& Opts) { + return llvm::make_unique( + std::make_shared(Opts, Consumer)); +} + +void indexModuleFile(serialization::ModuleFile &Mod, ASTReader &Reader, + IndexDataConsumer &DataConsumer, + const IndexingOptions& Opts) { + ASTContext &Ctx = Reader.getContext(); + IndexingContext IndexCtx(Opts, DataConsumer); + IndexCtx.setASTContext(Ctx); + DataConsumer.initialize(Ctx); + + if (Opts.IndexMacrosInPreprocessor) + indexPreprocessorMacros(Reader.getPreprocessor(), DataConsumer); + + for (const Decl *D : Reader.getModuleFileLevelDecls(Mod)) { + IndexCtx.indexTopLevelDecl(D); + } + DataConsumer.finish(); +} + +class IndexASTConsumer : public ASTConsumer { + std::shared_ptr Ctx; + +public: + IndexASTConsumer( + std::shared_ptr Ctx, + CompilerInstance &CI + ) : Ctx(Ctx) + { + CI.getPreprocessor().addPPCallbacks( llvm::make_unique(Ctx) ); + } + +protected: + void Initialize(ASTContext &Context) override { + Ctx->setASTContext(Context); + Ctx->getDataConsumer().initialize(Context); + } + + bool HandleTopLevelDecl(DeclGroupRef DG) override { + return Ctx->indexDeclGroupRef(DG); + } + + void HandleInterestingDecl(DeclGroupRef DG) override { + // Ignore deserialized decls. + } + + void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override { + Ctx->indexDeclGroupRef(DG); + } + + void HandleTranslationUnit(ASTContext &Ctx) override {} +}; + +GenerateIndexAction::GenerateIndexAction(std::shared_ptr DataConsumer, + const IndexingOptions& Opts +) : + DataConsumer(DataConsumer), + IndexCtx(new IndexingContext(Opts, *DataConsumer)) {} + +std::unique_ptr GenerateIndexAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { + + IndexCtx->getDataConsumer().setPreprocessor(CI.getPreprocessorPtr()); + return llvm::make_unique(IndexCtx, CI); +} + +void GenerateIndexAction::EndSourceFileAction() { + if (DataConsumer) + DataConsumer->finish(); +} + +} // namespace index +} // namespace clang \ No newline at end of file Index: clang/lib/Index/IndexAction.cpp =================================================================== --- /dev/null +++ clang/lib/Index/IndexAction.cpp @@ -0,0 +1,46 @@ +//===- IndexingAction.cpp - Frontend index action -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/IndexAction.h" + +#include "clang/Frontend/MultiplexConsumer.h" + +#include + +namespace clang { +namespace index { + +// Using distinct names for parameters in order to avoid confusion with name resolution in assert. +IndexActionWrapper::IndexActionWrapper( + std::unique_ptr IndexingActionParam, + std::unique_ptr WrappedActionParam +) : + WrapperFrontendAction(std::move(WrappedActionParam)), + IndexingAction(std::move(IndexingActionParam)) +{ + assert(IndexingAction); +} + +std::unique_ptr IndexActionWrapper::CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { + std::vector> Consumers; + auto OtherConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile); + if (OtherConsumer) + Consumers.push_back( std::move(OtherConsumer) ); + Consumers.push_back( IndexingAction->CreateASTConsumer(CI, InFile) ); + + return llvm::make_unique(std::move(Consumers)); +} + +void IndexActionWrapper::EndSourceFileAction() { + WrapperFrontendAction::EndSourceFileAction(); + IndexingAction->EndSourceFileAction(); +} + +} // namespace index +} // namespace clang \ No newline at end of file Index: clang/lib/Index/IndexOptions.cpp =================================================================== --- /dev/null +++ clang/lib/Index/IndexOptions.cpp @@ -0,0 +1,62 @@ +//===--- IndexOptions.h - Frontend index action -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/IndexOptions.h" +#include "clang/Index/IndexDataFormat.h" +#include "llvm/Support/Path.h" + +namespace clang { +namespace index { + +RecordingOptions::RecordingOptions( + const StringRef RootDir, + const bool RecordSymbolCodeGenName, + const bool RecordSystemDependencies, + const IncludesRecordingKind RecordIncludes +) : + RootDir(RootDir), + IndexDir( + llvm::Twine(RootDir) + .concat(llvm::sys::path::get_separator()) + .concat(store::getIndexDir()) + .str() + ), + UnitDir( + llvm::Twine(IndexDir) + .concat(llvm::sys::path::get_separator()) + .concat(store::getIndexUnitSubdir()) + .str() + ), + RecordDir( + llvm::Twine(IndexDir) + .concat(llvm::sys::path::get_separator()) + .concat(store::getIndexRecordSubdir()) + .str() + ), + RecordSymbolCodeGenName(RecordSymbolCodeGenName), + RecordSystemDependencies(RecordSystemDependencies), + RecordIncludes(RecordIncludes) +{ } + +IndexingOptions parseIndexGenerationOptions(const FrontendOptions &FEOpts) { + IndexingOptions IndexOpts; + if (FEOpts.IndexIgnoreSystemSymbols) { + IndexOpts.SystemSymbolFilter = + index::IndexingOptions::SystemSymbolFilterKind::None; + // TODO Do we actually ever use non-default values for the other members? + } + return IndexOpts; +} + +RecordingOptions parseIndexEmittingOptions(const FrontendOptions &FEOpts) { + // TODO Do we actually ever use non-default values for the other members? + return RecordingOptions(FEOpts.IndexStorePath, FEOpts.IndexRecordCodegenName); +} + +} // namespace index +} // namespace clang Index: clang/lib/Index/IndexPPCallbacks.h =================================================================== --- /dev/null +++ clang/lib/Index/IndexPPCallbacks.h @@ -0,0 +1,61 @@ +//===--- IndexPPCallbacks.h - Index unit serialization --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INDEX_INDEXPPCALLBACKS_H +#define LLVM_CLANG_INDEX_INDEXPPCALLBACKS_H + +#include "clang/Index/IndexingContext.h" +#include "clang/Lex/PPCallbacks.h" + +#include + +namespace llvm { + class BitstreamWriter; +} + +namespace clang { + class FileEntry; + class FileManager; + +namespace index { + +class IndexPPCallbacks : public PPCallbacks { + std::shared_ptr IndexCtx; + +public: + IndexPPCallbacks(std::shared_ptr IndexCtx) + : IndexCtx(IndexCtx) {} + + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range, const MacroArgs *Args) override { + IndexCtx->handleMacroReference(*MacroNameTok.getIdentifierInfo(), + Range.getBegin(), *MD.getMacroInfo()); + } + + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + IndexCtx->handleMacroDefined(*MacroNameTok.getIdentifierInfo(), + MacroNameTok.getLocation(), + *MD->getMacroInfo()); + } + + void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD, + const MacroDirective *Undef) override { + if (!MD.getMacroInfo()) // Ignore noop #undef. + return; + IndexCtx->handleMacroUndefined(*MacroNameTok.getIdentifierInfo(), + MacroNameTok.getLocation(), + *MD.getMacroInfo()); + } +}; + +} // end namespace index +} // end namespace clang + +#endif Index: clang/lib/Index/IndexRecordWriter.cpp =================================================================== --- /dev/null +++ clang/lib/Index/IndexRecordWriter.cpp @@ -0,0 +1,368 @@ +//===--- IndexRecordWriter.cpp - Index data per file --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Index/IndexDataFormat.h" +#include "clang/Index/IndexRecordWriter.h" +#include "clang/Index/USRGeneration.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Path.h" +#include "indexstore/indexstore.h" +#include "indexstore/Conversions.h" +#include "BitstreamUtil.h" +#include "llvm/Support/Errc.h" +#include "FSUtil.h" + +namespace clang { +namespace index { + +using namespace llvm; +using namespace store; + +void IndexRecordWriter::addDeclOccurence(SymbolRoleSet Roles, FileID FID, unsigned Offset, + const Decl *D, + ArrayRef Relations) { + assert(D->isCanonicalDecl() && + "Occurrences should be associated with their canonical decl"); + + auto getIdxForDecl = [this](const Decl *D) -> unsigned { + const auto MaybeNewDecl = IndexForDecl.insert( {D, DeclsNG.size()} ); + if (MaybeNewDecl.second) + DeclsNG.push_back(DeclInfo{D, SymbolRoleSet(), SymbolRoleSet()}); + return MaybeNewDecl.first->second; + }; + + const unsigned DeclIdx = getIdxForDecl(D); + DeclsNG[DeclIdx].Roles |= Roles; + + const uint64_t REC_DECLOCCURRENCE = 3; + + SourceManager &SM = D->getASTContext().getSourceManager(); + const unsigned Line = SM.getLineNumber(FID, Offset); + const unsigned Column = SM.getColumnNumber(FID, Offset); + + SmallVector OccurrenceData + { + REC_DECLOCCURRENCE, // FIXME: This is constant value. We don't need to store it. + DeclIdx + 1, + getIndexStoreRoles(Roles), + Line, + Column, + Relations.size() + }; + + OccurrenceData.reserve( + OccurrenceData.size() + + + 2 * Relations.size() + ); + for (auto &Rel : Relations) { + OccurrenceData.push_back( + getIndexStoreRoles(Rel.Roles) + ); + + const unsigned RelDeclIdx = getIdxForDecl(Rel.RelatedSymbol); + DeclsNG[RelDeclIdx].RelatedRoles |= Rel.Roles; + + OccurrenceData.push_back(RelDeclIdx + 1); + } + + OccurrencesNG.emplace(Offset, OccurrenceData); +} + + +static void writeHeader(BitstreamWriter &Stream) { + Stream.Emit('I', 8); + Stream.Emit('D', 8); + Stream.Emit('X', 8); + Stream.Emit('R', 8); +} + +static void writeBlockInfo(BitstreamWriter &Stream) { + SmallVector Record; + + Stream.EnterBlockInfoBlock(); +#define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record) +#define RECORD(X) emitRecordID(X, #X, Stream, Record) + + BLOCK(REC_VERSION_BLOCK); + RECORD(REC_VERSION); + + BLOCK(REC_DECLS_BLOCK); + RECORD(REC_DECLINFO); + + BLOCK(REC_DECLOFFSETS_BLOCK); + RECORD(REC_DECLOFFSETS); + + BLOCK(REC_DECLOCCURRENCES_BLOCK); + RECORD(REC_DECLOCCURRENCE); + +#undef RECORD +#undef BLOCK + Stream.ExitBlock(); +} + +static std::shared_ptr REC_VERSION_BLOCK_ID_Abbrev() { + static const std::shared_ptr CachedResult( + new BitCodeAbbrev( + { + BitCodeAbbrevOp(REC_VERSION), + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6) // Store format version + } + ) + ); + + return CachedResult; +} + +static void writeVersionInfo(BitstreamWriter &Stream) { + using namespace llvm::sys; + + Stream.EnterSubblock(REC_VERSION_BLOCK_ID, 3); + unsigned AbbrevCode = Stream.EmitAbbrev(REC_VERSION_BLOCK_ID_Abbrev()); + + const uint64_t Record[] = {REC_VERSION, getIndexFormatVersion()}; + Stream.EmitRecordWithAbbrev(AbbrevCode, Record); + + Stream.ExitBlock(); +} + +static std::shared_ptr DECLS_BLOCK_ID_Abbrev() { + static const std::shared_ptr CachedResult( + new BitCodeAbbrev( + { + BitCodeAbbrevOp(REC_DECLINFO), + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5), // Kind + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5), // SubKind + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5), // Language + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, SymbolPropertyBitNum), // Properties + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, SymbolRoleBitNum), // Roles + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, SymbolRoleBitNum), // Related Roles + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6), // Length of name in block + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6), // Length of USR in block + BitCodeAbbrevOp(BitCodeAbbrevOp::Blob) // Name + USR + CodeGen symbol name + } + ) + ); + + return CachedResult; +} + +static std::shared_ptr DECLOFFSETS_BLOCK_ID_Abbrev() { + static const std::shared_ptr CachedResult( + new BitCodeAbbrev( + { + BitCodeAbbrevOp(REC_DECLOFFSETS), + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32), // Number of Decls + BitCodeAbbrevOp(BitCodeAbbrevOp::Blob) // Offsets array + } + ) + ); + + return CachedResult; +} + +static std::shared_ptr DECLOCCURRENCES_BLOCK_ID_Abbrev() { + static const std::shared_ptr CachedResult( + new BitCodeAbbrev( + { + BitCodeAbbrevOp(REC_DECLOCCURRENCE), + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8), // Decl ID + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, SymbolRoleBitNum), // Roles + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12), // Line + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8), // Column + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4), // Num related + BitCodeAbbrevOp(BitCodeAbbrevOp::Array), // Related Roles/IDs + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16) // Roles or ID + } + ) + ); + + return CachedResult; +} + +static SmallString<256> getUSR(const Decl *D) { + SmallString<256> Buf; + bool Ignore = generateUSRForDecl(D, Buf); + if (Ignore) + return {}; + return Buf; +} + +void IndexRecordWriter::serialize(BitstreamWriter &Stream, const PrintingPolicy& Policy, + std::shared_ptr CGNameGen) const { + writeHeader(Stream); + writeBlockInfo(Stream); + writeVersionInfo(Stream); + + SmallVector DeclOffsets; + + { + Stream.EnterSubblock(REC_DECLS_BLOCK_ID, 3); + const unsigned AbbrevCode = Stream.EmitAbbrev( DECLS_BLOCK_ID_Abbrev() ); + +#ifndef NDEBUG + StringSet<> USRSet; + bool enableValidation = getenv("CLANG_INDEX_VALIDATION_CHECKS") != nullptr; +#endif + + DeclOffsets.reserve(DeclsNG.size()); + + llvm::SmallString<256> Scratch; + for (auto &Declaration : DeclsNG) { + DeclOffsets.push_back(Stream.GetCurrentBitNo()); + Scratch.clear(); + + const Decl *D = static_cast(Declaration.D); + auto Info = getSymbolInfo(D); + assert(Info.Kind != SymbolKind::Unknown); + + std::string Name; + std::string CGName; + if (auto *ND = dyn_cast(D)) { + DeclarationName DeclName = ND->getDeclName(); + if (!DeclName.isEmpty()) { + llvm::raw_string_ostream OS(Name); + DeclName.print(OS, Policy); + } + if (CGNameGen) { + llvm::raw_string_ostream OS(CGName); + CGNameGen->writeName(ND, OS); + } + } + + const SmallString<256> USR = getUSR(D); + assert(!USR.empty() && "Recorded decl without USR!"); + +#ifndef NDEBUG + if (enableValidation) { + bool IsNew = USRSet.insert(USR).second; + if (!IsNew) { + llvm::errs() << "Index: Duplicate USR! " << USR << "\n"; + // FIXME: print more information so it's easier to find the declaration. + } + } +#endif + + const uint64_t Record[] = + { + REC_DECLINFO, + getIndexStoreKind(Info.Kind), + getIndexStoreSubKind(Info.SubKind), + getIndexStoreLang(Info.Lang), + getIndexStoreProperties(Info.Properties), + getIndexStoreRoles(Declaration.Roles), + getIndexStoreRoles(Declaration.RelatedRoles), + Name.size(), + USR.size() + }; + + Stream.EmitRecordWithBlob(AbbrevCode, Record, + llvm::Twine(Name) + .concat(USR) + .concat(CGName) + .str() + ); + } + + Stream.ExitBlock(); + } + + { + Stream.EnterSubblock(REC_DECLOFFSETS_BLOCK_ID, 3); + const unsigned AbbrevCode = Stream.EmitAbbrev( DECLOFFSETS_BLOCK_ID_Abbrev() ); + const uint64_t Record[] = { REC_DECLOFFSETS, DeclOffsets.size() }; + StringRef DeclOffsetsData( + reinterpret_cast(DeclOffsets.data()), + sizeof(uint32_t) * DeclOffsets.size() + ); + + Stream.EmitRecordWithBlob(AbbrevCode, Record, DeclOffsetsData); + Stream.ExitBlock(); + } + + Stream.EnterSubblock(REC_DECLOCCURRENCES_BLOCK_ID, 3); + const unsigned AbbrevCode = Stream.EmitAbbrev( DECLOCCURRENCES_BLOCK_ID_Abbrev() ); + + for (auto &OffsetAndOccurrence : OccurrencesNG) { + Stream.EmitRecordWithAbbrev(AbbrevCode, OffsetAndOccurrence.second); + } + + Stream.ExitBlock(); +} + + +template +static void reportError(DiagnosticsEngine &Diag, const char (&Format)[N], const std::string& Filename, const std::string& Message) { + unsigned DiagID = Diag.getCustomDiagID( + DiagnosticsEngine::Error, Format); + Diag.Report(DiagID) << Filename << Message; +} + +/// Index record filename is the original source filename with hash of the index data as a suffix. +static std::string generateFilenameForIndexRecord(StringRef SourceName, const llvm::SmallString<512>& IndexRecordBuffer) { + const llvm::hash_code RecordHash = llvm::hash_combine_range(IndexRecordBuffer.begin(), IndexRecordBuffer.end()); + + std::string RecordFilename; + llvm::raw_string_ostream RN(RecordFilename); + RN << llvm::sys::path::filename(SourceName); + RN << "-" << llvm::APInt(64, RecordHash).toString(36, /*Signed=*/false); + return RecordFilename; +} + +// TODO Move SourceFileName to ctor. +llvm::Optional IndexRecordWriter::writeToDisk(StringRef SourceFileName, const RecordingOptions& RecordOpts, const PrintingPolicy& Policy, std::shared_ptr CGNameGen, DiagnosticsEngine &Diag) const { + + llvm::SmallString<512> IndexRecordBuffer; + { + llvm::BitstreamWriter Stream{IndexRecordBuffer}; + serialize(Stream, Policy, CGNameGen); + } + + const std::string RecordFilename = generateFilenameForIndexRecord(SourceFileName, IndexRecordBuffer); + + llvm::SmallString<256> RecordBucketSubdir(RecordOpts.RecordDir); + store::appendRecordBucketDir(RecordFilename, RecordBucketSubdir); + + if (std::error_code EC = sys::fs::create_directory(RecordBucketSubdir)) { + reportError(Diag, "failed to create directory '%0': %1", RecordBucketSubdir.str(), EC.message()); + return llvm::None; + } + + llvm::SmallString<256> RecordPath(RecordBucketSubdir); + store::appendRecordFilename(RecordFilename, RecordPath); + + if (std::error_code EC = + llvm::sys::fs::access(RecordPath.str().str().c_str(), llvm::sys::fs::AccessMode::Exist)) { + if (EC == llvm::errc::no_such_file_or_directory) { + // Create a unique file to write to so that we can move the result into place + // atomically. If this process crashes we don't want to interfere with any + // other concurrent processes. + // FIXME: We should also make sure we don't eat up all the disk in case we're crashing repeatedly. + SmallString<128> TempPath(RecordPath); + TempPath += "-temp-%%%%%%%%"; + std::string Error; + if ( atomicFileWrite(TempPath, RecordPath, IndexRecordBuffer, Error) ) { + // FIXME: This assumes getDiagnosticClient().BeginSourceFile() has been called. + reportError(Diag, "failed writing record '%0': %1", RecordFilename, Error); + return llvm::None; + } + } else { + reportError(Diag, "failed stating record file '%0': %1", RecordFilename, ""); + return llvm::None; + } + } + + return RecordFilename; +} + +} // end namespace index +} // end namespace clang \ No newline at end of file Index: clang/lib/Index/IndexUnitWriter.cpp =================================================================== --- /dev/null +++ clang/lib/Index/IndexUnitWriter.cpp @@ -0,0 +1,635 @@ +//===--- IndexUnitWriter.cpp - Index unit serialization -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/IndexUnitWriter.h" +#include "BitstreamUtil.h" +#include "clang/Index/IndexDataFormat.h" +#include "FSUtil.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Basic/Version.h" +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Bitstream/BitstreamWriter.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +namespace { +//FIXME: Seems ad-hoc - should this be in Basic/Version? +std::string getClangVersion() { + // Try picking the version from an Apple Clang tag. + const std::string RepositoryPath = clang::getClangRepositoryPath(); + llvm::StringRef BuildNumber(RepositoryPath); + if (BuildNumber.startswith("clang") ) { + const size_t DashOffset = BuildNumber.find('-'); + if (DashOffset != llvm::StringRef::npos) + return BuildNumber.substr(DashOffset + 1); + } + // Fallback to the generic version. + return CLANG_VERSION_STRING; +} +} + +namespace clang { +namespace index { + +using namespace clang::index::store; +using namespace llvm; +using namespace llvm::sys; + +unsigned IndexUnitWriter::addModule(writer::OpaqueModule Mod) { + if (!Mod) + return 0; + const auto Inserted = ModToIdx.insert({Mod, ModToIdx.size() + 1}); + if (Inserted.second) { + SmallString<64> ModuleName; + StringRef name = GetInfoForModuleFn(Mod, ModuleName).Name; + const size_t ModuleNameOffset = ModuleNamesBuf.size(); + ModuleNamesBuf += name; + + Modules.push_back( + { + UNIT_MODULE, + ModuleNameOffset, + name.size() + } + ); + } + return Inserted.first->second; +} + +IndexUnitWriter::IndexUnitWriter(FileManager &FileMgr, + const RecordingOptions& RecOpts, + StringRef ProviderIdentifier, + StringRef ProviderVersion, + StringRef OutputFile, + StringRef AbsPathToOutputFile, + const FileEntry *MainFile, + const llvm::Optional& ModuleData, + bool IsDebugCompilation, + StringRef TargetTriple, + StringRef WorkDir, + StringRef SysrootPath, + writer::ModuleInfoWriterCallback GetInfoForModule) +: RecOpts(RecOpts), + ProviderIdentifier(ProviderIdentifier), + ProviderVersion(ProviderVersion), + OutputFile(OutputFile), + AbsPathToOutputFile(AbsPathToOutputFile), + MainFile(MainFile), + ModuleData(ModuleData), + IsDebugCompilation(IsDebugCompilation), + TargetTriple(TargetTriple), + WorkDir(WorkDir), + SysrootPath(SysrootPath), + PathStore(WorkDir, SysrootPath), + GetInfoForModuleFn(GetInfoForModule) +{} + +void IndexUnitWriter::addSourceFile(const FileEntry *File, bool IsSystem, + writer::OpaqueModule Mod) { + assert(File); + + SourceFiles[File] = std::array + { + UNIT_DEPENDENCY, + UNIT_DEPEND_KIND_FILE, + IsSystem, + static_cast( PathStore.getPathIndex(File) + 1 ), + addModule(Mod), + 0, // Reserved. + 0 // Reserved. + }; +} + +void IndexUnitWriter::addIndexRecord(StringRef FileName, const FileEntry *SourceFile, + bool IsSystem, writer::OpaqueModule Mod) { + assert(SourceFile); + + SourceFileHasARecord.insert(SourceFile); + + IndexRecordDependencies.push_back( + std::make_pair>( + FileName, + { + UNIT_DEPENDENCY, + UNIT_DEPEND_KIND_RECORD, + IsSystem, + static_cast(PathStore.getPathIndex(SourceFile) + 1), + addModule(Mod), + 0, // Reserved. + 0 // Reserved. + } + ) + ); +} + +void IndexUnitWriter::addIndexUnit( + const FileEntry *ASTFile, + StringRef AbsolutePath, + bool IsSystem, + writer::OpaqueModule Mod, + bool withoutUnitName +) { + assert(ASTFile); + if (!ASTFilesOfSeenIndexUnits.insert(ASTFile).second) + return; + + SmallString<64> UnitName; + if (!withoutUnitName) { + getUnitNameForAbsoluteOutputFile(AbsolutePath, UnitName); + } + + IndexUnitDependencies.emplace_back( + UnitName, + std::array{ + UNIT_DEPENDENCY, + UNIT_DEPEND_KIND_UNIT, + IsSystem, + static_cast( PathStore.getPathIndex(ASTFile) + 1 ), + addModule(Mod), + 0, // Reserved. + 0 // Reserved. + } + ); +} + +void IndexUnitWriter::addIncludedFile(const FileEntry *IncludingFile, unsigned LineNo, + const FileEntry *IncludedFile) { + IncludedFiles.push_back( + { + UNIT_INCLUDE, // FIXME: This is static data which don't have to be stored here. + static_cast( PathStore.getPathIndex(IncludingFile) + 1 ), + LineNo, + static_cast( PathStore.getPathIndex(IncludedFile) + 1 ) + } + ); +}; + +static void writeBlockInfo(BitstreamWriter &Stream) { + SmallVector Record; + + Stream.EnterBlockInfoBlock(); +#define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record) +#define RECORD(X) emitRecordID(X, #X, Stream, Record) + + BLOCK(UNIT_VERSION_BLOCK); + RECORD(UNIT_VERSION); + + BLOCK(UNIT_INFO_BLOCK); + RECORD(UNIT_INFO); + + BLOCK(UNIT_DEPENDENCIES_BLOCK); + RECORD(UNIT_DEPENDENCY); + + BLOCK(UNIT_INCLUDES_BLOCK); + RECORD(UNIT_INCLUDE); + + BLOCK(UNIT_PATHS_BLOCK); + RECORD(UNIT_PATH); + RECORD(UNIT_PATH_BUFFER); + + BLOCK(UNIT_MODULES_BLOCK); + RECORD(UNIT_MODULE); + RECORD(UNIT_MODULE_BUFFER); + +#undef RECORD +#undef BLOCK + Stream.ExitBlock(); +} + +static std::shared_ptr UNIT_VERSION_BLOCK_ID_Abbrev() { + static const std::shared_ptr CachedResult( + new BitCodeAbbrev( + { + BitCodeAbbrevOp(UNIT_VERSION), + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6) // Store format version + } + ) + ); + + return CachedResult; +} + +static void writeVersionInfo(BitstreamWriter &Stream) { + using namespace llvm::sys; + + Stream.EnterSubblock(UNIT_VERSION_BLOCK_ID, 3); + unsigned AbbrevCode = Stream.EmitAbbrev( UNIT_VERSION_BLOCK_ID_Abbrev()); + + const uint64_t Record[2] { + UNIT_VERSION, + getIndexFormatVersion() + }; + Stream.EmitRecordWithAbbrev(AbbrevCode, Record); + + Stream.ExitBlock(); +} + +bool IndexUnitWriter::writeToDisk(std::string &Error) const { + SmallString<512> BicodeRepresentation = getBitcodeReprentation(Error); + + SmallString<256> UnitPath = + StringRef( + llvm::Twine(RecOpts.UnitDir) + .concat(llvm::sys::path::get_separator()) + .str() + ); + + getUnitNameForAbsoluteOutputFile(AbsPathToOutputFile, UnitPath); + + SmallString<128> TempPath; + TempPath = path::parent_path(RecOpts.UnitDir); + TempPath += llvm::sys::path::get_separator().str(); + TempPath += path::filename(UnitPath); + TempPath += "-%%%%%%%%"; + + return atomicFileWrite(TempPath, UnitPath, BicodeRepresentation, Error); +} + +SmallString<512> IndexUnitWriter::getBitcodeReprentation(std::string &Error) const { + using namespace llvm::sys; + + SmallString<512> Buffer; + BitstreamWriter Stream(Buffer); + Stream.Emit('I', 8); + Stream.Emit('D', 8); + Stream.Emit('X', 8); + Stream.Emit('U', 8); + + writeBlockInfo(Stream); + writeVersionInfo(Stream); + writeUnitInfo(Stream); + writeDependencies(Stream); + writeIncludes(Stream); + writePaths(Stream); + writeModules(Stream); + + return Buffer; +} + +static std::shared_ptr UNIT_INFO_BLOCK_ID_Abbrev() { + static const std::shared_ptr CachedResult( + new BitCodeAbbrev( + { + BitCodeAbbrevOp(UNIT_INFO), + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1), // IsSystemUnit + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10), // WorkDir offset + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8), // WorkDir size + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10), // OutputFile offset + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8), // OutputFile size + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10), // Sysroot offset + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8), // Sysroot size + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10), // Main path id + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1), // IsDebugCompilation + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1), // IsModuleUnit + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5), // Module name size + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5), // ProviderIdentifier size + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5), // ProviderVersion size + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5), // ProviderDataVersion + BitCodeAbbrevOp(BitCodeAbbrevOp::Blob) // Module name + ProviderIdentifier + ProviderVersion + target triple + } + ) + ); + + return CachedResult; +} + +void IndexUnitWriter::writeUnitInfo(llvm::BitstreamWriter &Stream) const { + Stream.EnterSubblock(UNIT_INFO_BLOCK_ID, 3); + unsigned AbbrevCode = Stream.EmitAbbrev(UNIT_INFO_BLOCK_ID_Abbrev()); + + const std::string ModuleName = + ModuleData.hasValue() + ? ModuleData->Name + : ""; + + const uint64_t Record[15]{ + UNIT_INFO, + ModuleData.hasValue() && ModuleData->IsSystem, // We don't expect compilation of any source code that would be considered system unless it's a dependency in form of module. + PathStore.getPathOffset(WorkDir), + WorkDir.size(), + PathStore.getPathOffset(OutputFile), + OutputFile.size(), + PathStore.getPathOffset(SysrootPath), + SysrootPath.size(), + static_cast( PathStore.getPathIndex(MainFile) + 1 ), // Make 1-based with 0=invalid + IsDebugCompilation, + ModuleData.hasValue(), + ModuleName.size(), + ProviderIdentifier.size(), + ProviderVersion.size(), + // ProviderDataVersion is reserved. Not sure it is a good to idea to have + // clients consider the specifics of a 'provider data version', but reserving + // to avoid store format version change in case there is a use case in the + // future. + 0 // ProviderDataVersion + }; + const std::string InfoStrings = + llvm::Twine(ModuleName) + .concat(ProviderIdentifier) + .concat(ProviderVersion) + .concat(TargetTriple) + .str(); + + Stream.EmitRecordWithBlob(AbbrevCode, Record, InfoStrings); + + Stream.ExitBlock(); +} + +static std::shared_ptr UNIT_DEPENDENCIES_BLOCK_ID_Abbrev() { + static const std::shared_ptr CachedResult( + new BitCodeAbbrev( + { + BitCodeAbbrevOp(UNIT_DEPENDENCY), + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, UnitDependencyKindBitNum), // Dependency kind + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1), // IsSystem + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10), // PathIndex (1-based, 0 = none) + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8), // ModuleIndex (1-based, 0 = none) + // Reserved. These used to be time_t & file size but we decided against + // writing these in order to get reproducible build products (index data + // output being the same with the same inputs). Keep these reserved for the + // future, for coming up with a better scheme to track state of dependencies + // without using modification time. + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 0), // Reserved + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 0), // Reserved + BitCodeAbbrevOp(BitCodeAbbrevOp::Blob) // Name + } + ) + ); + + return CachedResult; +} + +void IndexUnitWriter::writeDependencies(llvm::BitstreamWriter &Stream) const { + Stream.EnterSubblock(UNIT_DEPENDENCIES_BLOCK_ID, 3); + + unsigned AbbrevCode = Stream.EmitAbbrev( UNIT_DEPENDENCIES_BLOCK_ID_Abbrev() ); + + for (auto &IdxUnit : IndexUnitDependencies) { + Stream.EmitRecordWithBlob(AbbrevCode, IdxUnit.second, IdxUnit.first); + } + + for (auto &recordData : IndexRecordDependencies) { + Stream.EmitRecordWithBlob(AbbrevCode, recordData.second, recordData.first); + } + + for (const auto &FileAndData : SourceFiles) { + if (SourceFileHasARecord.count(FileAndData.first) > 0) + continue; + Stream.EmitRecordWithBlob(AbbrevCode, FileAndData.second, StringRef()); + } + + Stream.ExitBlock(); +} + +static std::shared_ptr UNIT_INCLUDES_BLOCK_ID_Abbrev() { + static const std::shared_ptr CachedResult( + new BitCodeAbbrev( + { + BitCodeAbbrevOp(UNIT_INCLUDE), + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10), // source path index (1-based, 0 = no path) + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12), // source include line + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10) // target path index (1-based, 0 = no path) + } + ) + ); + + return CachedResult; +} + +void IndexUnitWriter::writeIncludes(llvm::BitstreamWriter &Stream) const { + Stream.EnterSubblock(UNIT_INCLUDES_BLOCK_ID, 3); + + unsigned AbbrevCode = Stream.EmitAbbrev( UNIT_INCLUDES_BLOCK_ID_Abbrev() ); + + for (const auto &IncludeDirective : IncludedFiles) { + Stream.EmitRecordWithAbbrev(AbbrevCode, IncludeDirective); + } + + Stream.ExitBlock(); +} + +static std::shared_ptr UNIT_PATHS_BLOCK_ID_Paths_Abbrev() { + static const std::shared_ptr CachedResult( + new BitCodeAbbrev( + { + BitCodeAbbrevOp(UNIT_PATH), + BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, UnitFilePathPrefixKindBitNum), // Path prefix kind + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10), // DirPath offset + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8), // DirPath size + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10), // Filename offset + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6) // Filename size + } + ) + ); + + return CachedResult; +} + +static std::shared_ptr UNIT_PATHS_BLOCK_ID_Path_Buffers_Abbrev() { + static const std::shared_ptr CachedResult( + new BitCodeAbbrev( + { + BitCodeAbbrevOp(UNIT_PATH_BUFFER), + BitCodeAbbrevOp(BitCodeAbbrevOp::Blob) // Paths buffer + } + ) + ); + + return CachedResult; +} + +void IndexUnitWriter::writePaths(llvm::BitstreamWriter &Stream) const { + Stream.EnterSubblock(UNIT_PATHS_BLOCK_ID, 3); + + const unsigned PathAbbrevCode = Stream.EmitAbbrev( UNIT_PATHS_BLOCK_ID_Paths_Abbrev() ); + const unsigned PathBufferAbbrevCode = Stream.EmitAbbrev( UNIT_PATHS_BLOCK_ID_Path_Buffers_Abbrev() ); + + for(auto &BitPath: PathStore.getBitPaths()) { + const uint64_t Record[6] { + UNIT_PATH, + BitPath.PrefixKind, + BitPath.Dir.Offset, + BitPath.Dir.Size, + BitPath.Filename.Offset, + BitPath.Filename.Size + }; + Stream.EmitRecordWithAbbrev(PathAbbrevCode, Record); + } + + Stream.EmitRecordWithBlob(PathBufferAbbrevCode, UNIT_PATH_BUFFER, PathStore.getPathsBuffer()); + + Stream.ExitBlock(); +} + +static std::shared_ptr UNIT_MODULES_BLOCK_ID_Module_Abbrev() { + static const std::shared_ptr CachedResult( + new BitCodeAbbrev( + { + BitCodeAbbrevOp(UNIT_MODULE), + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 9), // Module name offset + BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6) // Module name size + } + ) + ); + + return CachedResult; +} + +static std::shared_ptr UNIT_MODULES_BLOCK_ID_Module_Buffer_Abbrev() { + static const std::shared_ptr CachedResult( + new BitCodeAbbrev( + { + BitCodeAbbrevOp(UNIT_MODULE_BUFFER), + BitCodeAbbrevOp(BitCodeAbbrevOp::Blob) // Module names buffer + } + ) + ); + + return CachedResult; +} + +void IndexUnitWriter::writeModules(llvm::BitstreamWriter &Stream) const { + Stream.EnterSubblock(UNIT_MODULES_BLOCK_ID, 3); + unsigned AbbrevCode = Stream.EmitAbbrev(UNIT_MODULES_BLOCK_ID_Module_Abbrev()); + unsigned BufferAbbrevCode = Stream.EmitAbbrev(UNIT_MODULES_BLOCK_ID_Module_Buffer_Abbrev()); + + for (auto &Module : Modules) { + Stream.EmitRecordWithAbbrev(AbbrevCode, Module); + } + + Stream.EmitRecordWithBlob(BufferAbbrevCode, UNIT_MODULE_BUFFER, ModuleNamesBuf.str()); + Stream.ExitBlock(); +} + +static writer::ModuleInfo getModuleInfo(writer::OpaqueModule mod, + SmallVectorImpl &Scratch) { + assert(mod); + writer::ModuleInfo info; + const std::string fullName = + static_cast(mod)->getFullModuleName(); + unsigned offset = Scratch.size(); + Scratch.append(fullName.begin(), fullName.end()); + info.Name = StringRef(Scratch.data() + offset, fullName.size()); + return info; +} + +IndexUnitWriter makeIndexUnitWriter( + const CompilerInstance &CI, + const RecordingOptions& RecordOpts, + StringRef OutputFile, + const FileEntry *MainFile, + Module *UnitModule +) { + assert(MainFile == nullptr || UnitModule == nullptr); + + SmallString<256> AbsOutputFilePath(OutputFile); + CI.getFileManager().makeAbsolutePath(AbsOutputFilePath); + + llvm::Optional ModuleData = [UnitModule]() -> llvm::Optional { + if (UnitModule) { + return ModuleIndexData{ + UnitModule->getFullModuleName(), + static_cast(UnitModule->IsSystem) + }; + } + return llvm::None; + }(); + + SmallString<128> WorkDir; + if (!CI.getFileManager().getFileSystemOpts().WorkingDir.empty()) { + WorkDir = CI.getFileManager().getFileSystemOpts().WorkingDir; + if (!llvm::sys::path::is_absolute(WorkDir)) { + llvm::sys::fs::make_absolute(WorkDir); + } + } else { + std::error_code EC = llvm::sys::fs::current_path(WorkDir); + if (EC) { + // FIXME: error handling + llvm_unreachable("failed to determine current working directory"); + } + } + + return IndexUnitWriter{ + CI.getFileManager(), RecordOpts, "clang", + getClangVersion(), OutputFile, + AbsOutputFilePath, + MainFile, + ModuleData, + CI.getCodeGenOpts().OptimizationLevel == 0, + CI.getTargetOpts().Triple, WorkDir.str(), CI.getHeaderSearchOpts().Sysroot, getModuleInfo + }; +} + +bool initIndexDirectory(const RecordingOptions& RecordingOpts, + std::string &Error/* <- kill */) { + using namespace llvm::sys; + auto CreateDir = [&](StringRef DirPath){ + std::error_code EC = fs::create_directories(DirPath); + if (EC) { + llvm::raw_string_ostream Err(Error); + Err << "failed to create directory '" << DirPath << "': " << EC.message(); + return true; + } + return false; + }; + if (CreateDir(RecordingOpts.IndexDir)) + return true; + if (CreateDir(RecordingOpts.RecordDir)) + return true; + if (CreateDir(RecordingOpts.UnitDir)) + return true; + + return false; +} + +void getUnitNameForAbsoluteOutputFile(StringRef FilePath, + SmallVectorImpl &Str) { + StringRef Fname = sys::path::filename(FilePath); + Str.append(Fname.begin(), Fname.end()); + Str.push_back('-'); + llvm::hash_code PathHashVal = llvm::hash_value(FilePath); + llvm::APInt(64, PathHashVal).toString(Str, 36, /*Signed=*/false); +} + +llvm::Optional doesIndexUnitForModuleExist(StringRef ModuleFilePath, const FileManager& FileMgr, const RecordingOptions &RecOpts +) { + SmallString<256> UnitPath( + StringRef( + llvm::Twine(RecOpts.UnitDir) + .concat(llvm::sys::path::get_separator().str() + ).str() + ) + ); + + SmallString<256> AbsPath(ModuleFilePath); + FileMgr.makeAbsolutePath(AbsPath); + + getUnitNameForAbsoluteOutputFile(AbsPath, UnitPath); + + llvm::sys::fs::file_status UnitStat; + if (std::error_code EC = llvm::sys::fs::status(UnitPath.c_str(), UnitStat)) { + if (EC == llvm::errc::no_such_file_or_directory) + return false; + + return None; + } + return true; +} + +} // namespace index +} // namespace clang \ No newline at end of file Index: clang/lib/Index/IndexingContext.cpp =================================================================== --- clang/lib/Index/IndexingContext.cpp +++ clang/lib/Index/IndexingContext.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "IndexingContext.h" +#include "clang/Index/IndexingContext.h" #include "clang/Basic/SourceLocation.h" #include "clang/Index/IndexDataConsumer.h" #include "clang/AST/ASTContext.h" @@ -119,12 +119,7 @@ if (FID.isInvalid()) return true; - bool Invalid = false; - const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); - if (Invalid || !SEntry.isFile()) - return true; - - if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { + if (isSystemFile(FID)) { switch (IndexOpts.SystemSymbolFilter) { case IndexingOptions::SystemSymbolFilterKind::None: return true; @@ -147,6 +142,7 @@ return DataConsumer.handleModuleOccurence(ImportD, Mod, Roles, Loc); } +// TODO Isn't for example Sema better place to do this? bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) { TemplateSpecializationKind TKind = TSK_Undeclared; if (const ClassTemplateSpecializationDecl * @@ -193,6 +189,57 @@ return true; } +void IndexingContext::setSysrootPath(StringRef path) { + // Ignore sysroot path if it points to root, otherwise every header will be + // treated as system one. + // FIXMIE: make this portable + if (path == "/") + path = StringRef(); + SysrootPath = path; +} + +bool IndexingContext::isSystemFile(FileID FID) { + if (LastFileCheck.first == FID) + return LastFileCheck.second; + + auto cacheResult = [&](bool res) -> bool { + LastFileCheck = { FID, res }; + return res; + }; + + bool Invalid = false; + const SrcMgr::SLocEntry &SEntry = + Ctx->getSourceManager().getSLocEntry(FID, &Invalid); + if (Invalid || !SEntry.isFile()) + return cacheResult(false); + + const SrcMgr::FileInfo &FI = SEntry.getFile(); + if (FI.getFileCharacteristic() != SrcMgr::C_User) + return cacheResult(true); + + auto *CC = FI.getContentCache(); + if (!CC) + return cacheResult(false); + auto *FE = CC->OrigEntry; + if (!FE) + return cacheResult(false); + + if (SysrootPath.empty()) + return cacheResult(false); + + // Check if directory is in sysroot so that we can consider system headers + // even the headers found via a user framework search path, pointing inside + // sysroot. + auto dirEntry = FE->getDir(); + auto pair = DirEntries.insert(std::make_pair(dirEntry, false)); + bool &isSystemDir = pair.first->second; + bool wasInserted = pair.second; + if (wasInserted) { + isSystemDir = StringRef(dirEntry->getName()).startswith(SysrootPath); + } + return cacheResult(isSystemDir); +} + static const CXXRecordDecl * getDeclContextForTemplateInstationPattern(const Decl *D) { if (const auto *CTSD = @@ -355,7 +402,7 @@ const Expr *OrigE, const Decl *OrigD, const DeclContext *ContainerDC) { - if (D->isImplicit() && !isa(D)) + if (D->isImplicit() && !(isa(D) || isa(D))) return true; if (!isa(D) || shouldSkipNamelessDecl(cast(D))) return true; @@ -365,12 +412,7 @@ if (FID.isInvalid()) return true; - bool Invalid = false; - const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid); - if (Invalid || !SEntry.isFile()) - return true; - - if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) { + if (isSystemFile(FID)) { switch (IndexOpts.SystemSymbolFilter) { case IndexingOptions::SystemSymbolFilterKind::None: return true; Index: clang/lib/Index/PathStorage.cpp =================================================================== --- /dev/null +++ clang/lib/Index/PathStorage.cpp @@ -0,0 +1,70 @@ +#include "clang/Index/PathStorage.h" + +using namespace llvm; +using namespace clang; + +DirBitPath::DirBitPath(UnitFilePathPrefixKind Kind, + BitPathComponent Dir) : PrefixKind(Kind), Dir(Dir) {} +DirBitPath::DirBitPath() : PrefixKind(UNIT_PATH_PREFIX_NONE) {} + +PathStorage::PathStorage(StringRef workDir, StringRef sysrootPath) { + WorkDir = workDir; + if (sysrootPath == "/") + sysrootPath = StringRef(); + SysrootPath = sysrootPath; +} + +int PathStorage::getPathIndex(const FileEntry *FE) { + if (!FE) + return -1; + auto Pair = FileToIndex.insert(std::make_pair(FE, FileBitPaths.size())); + bool IsNew = Pair.second; + size_t Index = Pair.first->getSecond(); + + if (IsNew) { + StringRef Filename = sys::path::filename(FE->getName()); + DirBitPath Dir = getDirBitPath(sys::path::parent_path(FE->getName())); + FileBitPaths.emplace_back(Dir.PrefixKind, Dir.Dir, + BitPathComponent(getPathOffset(Filename), + Filename.size())); + } + return Index; +} + +size_t PathStorage::getPathOffset(StringRef Path) { + if (Path.empty()) + return 0; + size_t offset = PathsBuf.size(); + PathsBuf += Path; + return offset; +} + +static bool isPathInDir(StringRef dir, StringRef path) { + if (dir.empty() || !path.startswith(dir)) + return false; + StringRef rest = path.drop_front(dir.size()); + return !rest.empty() && sys::path::is_separator(rest.front()); +} + +DirBitPath PathStorage::getDirBitPath(StringRef dirStr) { + auto pair = Dirs.insert(std::make_pair(dirStr, DirBitPath())); + bool isNew = pair.second; + auto &dirPath = pair.first->second; + + if (isNew) { + if (isPathInDir(SysrootPath, dirStr)) { + dirPath.PrefixKind = UNIT_PATH_PREFIX_SYSROOT; + dirStr = dirStr.drop_front(SysrootPath.size()); + while (!dirStr.empty() && dirStr[0] == '/') + dirStr = dirStr.drop_front(); + } else if (isPathInDir(WorkDir, dirStr)) { + dirPath.PrefixKind = UNIT_PATH_PREFIX_WORKDIR; + dirStr = dirStr.drop_front(WorkDir.size()); + while (!dirStr.empty() && dirStr[0] == '/') + dirStr = dirStr.drop_front(); + } + dirPath.Dir.Offset = getPathOffset(dirStr); + dirPath.Dir.Size = dirStr.size(); + } + return dirPath; +} Index: clang/lib/IndexDataStore/CMakeLists.txt =================================================================== --- /dev/null +++ clang/lib/IndexDataStore/CMakeLists.txt @@ -0,0 +1,11 @@ +set(LLVM_LINK_COMPONENTS + Support + ) + +add_clang_library(clangIndexDataStore + IndexDataStore.cpp + + LINK_LIBS + clangDirectoryWatcher + clangIndex + ) Index: clang/lib/IndexDataStore/IndexDataStore.cpp =================================================================== --- /dev/null +++ clang/lib/IndexDataStore/IndexDataStore.cpp @@ -0,0 +1,228 @@ +//===--- IndexDataStore.cpp - Index data store info -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Index/IndexDataStore.h" +#include "clang/Index/IndexDataFormat.h" +#include "clang/DirectoryWatcher/DirectoryWatcher.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace clang::index; +using namespace clang::index::store; +using namespace llvm; + +namespace { + +class UnitEventHandlerData { + mutable sys::Mutex Mtx; + IndexDataStore::UnitEventHandler Handler; + +public: + void setHandler(IndexDataStore::UnitEventHandler handler) { + sys::ScopedLock L(Mtx); + Handler = std::move(handler); + } + IndexDataStore::UnitEventHandler getHandler() const { + sys::ScopedLock L(Mtx); + return Handler; + } +}; + +class IndexDataStoreImpl { + std::string FilePath; + std::shared_ptr TheUnitEventHandlerData; + std::unique_ptr DirWatcher; + +public: + explicit IndexDataStoreImpl(StringRef indexStorePath) + : FilePath(indexStorePath) { + TheUnitEventHandlerData = std::make_shared(); + } + + StringRef getFilePath() const { return FilePath; } + bool foreachUnitName(bool sorted, + llvm::function_ref receiver); + void setUnitEventHandler(IndexDataStore::UnitEventHandler Handler); + bool startEventListening(bool waitInitialSync, std::string &Error); + void stopEventListening(); + void discardUnit(StringRef UnitName); + void discardRecord(StringRef RecordName); + void purgeStaleData(); +}; + +} // anonymous namespace + +bool IndexDataStoreImpl::foreachUnitName(bool sorted, + llvm::function_ref receiver) { + SmallString<128> UnitPath; + UnitPath = FilePath; + appendUnitSubDir(UnitPath); + + std::vector filenames; + + std::error_code EC; + for (auto It = sys::fs::directory_iterator(UnitPath, EC), + End = sys::fs::directory_iterator(); + !EC && It != End; It.increment(EC)) { + StringRef unitName = sys::path::filename(It->path()); + if (!sorted) { + if (!receiver(unitName)) + return false; + } else { + filenames.push_back(unitName); + } + } + + if (sorted) { + std::sort(filenames.begin(), filenames.end()); + for (auto &fname : filenames) + if (!receiver(fname)) + return false; + } + return true; +} + +void IndexDataStoreImpl::setUnitEventHandler(IndexDataStore::UnitEventHandler handler) { + TheUnitEventHandlerData->setHandler(std::move(handler)); +} + +bool IndexDataStoreImpl::startEventListening(bool waitInitialSync, std::string &Error) { + if (DirWatcher) { + Error = "event listener already active"; + return true; + } + + SmallString<128> UnitPath; + UnitPath = FilePath; + appendUnitSubDir(UnitPath); + + auto localUnitEventHandlerData = TheUnitEventHandlerData; + auto OnUnitsChange = [localUnitEventHandlerData](ArrayRef Events, bool isInitial) { + SmallVector UnitEvents; + UnitEvents.reserve(Events.size()); + for (const DirectoryWatcher::Event &evt : Events) { + IndexDataStore::UnitEventKind K; + StringRef UnitName = sys::path::filename(evt.Filename); + switch (evt.Kind) { + case DirectoryWatcher::EventKind::Added: + K = IndexDataStore::UnitEventKind::Added; break; + case DirectoryWatcher::EventKind::Removed: + K = IndexDataStore::UnitEventKind::Removed; break; + case DirectoryWatcher::EventKind::Modified: + K = IndexDataStore::UnitEventKind::Modified; break; + case DirectoryWatcher::EventKind::DirectoryDeleted: + K = IndexDataStore::UnitEventKind::DirectoryDeleted; + UnitName = StringRef(); + break; + } + UnitEvents.push_back( + IndexDataStore::UnitEvent{K, UnitName, llvm::sys::TimePoint<>{}}); + } + + if (auto handler = localUnitEventHandlerData->getHandler()) { + IndexDataStore::UnitEventNotification EventNote{isInitial, UnitEvents}; + handler(EventNote); + } + }; + + DirWatcher = DirectoryWatcher::create(UnitPath.str(), OnUnitsChange, + waitInitialSync, Error); + if (!DirWatcher) + return true; + + return false; +} + +void IndexDataStoreImpl::stopEventListening() { + DirWatcher.reset(); +} + +void IndexDataStoreImpl::discardUnit(StringRef UnitName) { + SmallString<128> UnitPath; + UnitPath = FilePath; + appendUnitSubDir(UnitPath); + appendUnitBucketDir(UnitName, UnitPath); + sys::fs::remove(UnitPath); +} + +void IndexDataStoreImpl::discardRecord(StringRef RecordName) { + // TODO check - is this correct or is the order of appended elements opposite? + SmallString<128> RecordPath; + RecordPath = FilePath; + appendRecordSubDir(RecordPath); + appendRecordBucketDir(RecordName, RecordPath); + appendRecordFilename(RecordName, RecordPath); + sys::fs::remove(RecordPath); +} + +void IndexDataStoreImpl::purgeStaleData() { + // FIXME: Implement. +} + + +std::unique_ptr +IndexDataStore::create(StringRef IndexStorePath, std::string &Error) { + if (!sys::fs::exists(IndexStorePath)) { + raw_string_ostream OS(Error); + OS << "index store path does not exist: " << IndexStorePath; + return nullptr; + } + + return std::unique_ptr( + new IndexDataStore(new IndexDataStoreImpl(IndexStorePath))); +} + +#define IMPL static_cast(Impl) + +IndexDataStore::~IndexDataStore() { + delete IMPL; +} + +StringRef IndexDataStore::getFilePath() const { + return IMPL->getFilePath(); +} + +bool IndexDataStore::foreachUnitName(bool sorted, + llvm::function_ref receiver) { + return IMPL->foreachUnitName(sorted, std::move(receiver)); +} + +unsigned IndexDataStore::getFormatVersion() { + return clang::index::store::getIndexFormatVersion(); +} + +void IndexDataStore::setUnitEventHandler(UnitEventHandler Handler) { + return IMPL->setUnitEventHandler(std::move(Handler)); +} + +bool IndexDataStore::startEventListening(bool waitInitialSync, std::string &Error) { + return IMPL->startEventListening(waitInitialSync, Error); +} + +void IndexDataStore::stopEventListening() { + return IMPL->stopEventListening(); +} + +void IndexDataStore::discardUnit(StringRef UnitName) { + IMPL->discardUnit(UnitName); +} + +void IndexDataStore::discardRecord(StringRef RecordName) { + IMPL->discardRecord(RecordName); +} + +void IndexDataStore::purgeStaleData() { + IMPL->purgeStaleData(); +} Index: llvm/include/llvm/ADT/ArrayRef.h =================================================================== --- llvm/include/llvm/ADT/ArrayRef.h +++ llvm/include/llvm/ADT/ArrayRef.h @@ -481,6 +481,12 @@ return Vec; } + /// Construct an ArrayRef from a std::array. + template + ArrayRef makeArrayRef(const std::array &Arr) { + return Arr; + } + /// Construct an ArrayRef from an ArrayRef (no-op) (const) template ArrayRef makeArrayRef(const ArrayRef &Vec) { return Vec; Index: llvm/include/llvm/Bitstream/BitCodes.h =================================================================== --- llvm/include/llvm/Bitstream/BitCodes.h +++ llvm/include/llvm/Bitstream/BitCodes.h @@ -166,6 +166,11 @@ SmallVector OperandList; public: + BitCodeAbbrev() = default; + + explicit BitCodeAbbrev(std::initializer_list OperandList) + : OperandList(OperandList) { } + unsigned getNumOperandInfos() const { return static_cast(OperandList.size()); }