diff options
Diffstat (limited to 'clangd/Headers.h')
-rw-r--r-- | clangd/Headers.h | 89 |
1 files changed, 63 insertions, 26 deletions
diff --git a/clangd/Headers.h b/clangd/Headers.h index 987832fc..2abf27c6 100644 --- a/clangd/Headers.h +++ b/clangd/Headers.h @@ -45,29 +45,47 @@ struct Inclusion { Path Resolved; // Resolved path of included file. Empty if not resolved. }; +// Information captured about the inclusion graph in a translation unit. +// This includes detailed information about the direct #includes, and summary +// information about all transitive includes. +// +// It should be built incrementally with collectIncludeStructureCallback(). +// When we build the preamble, we capture and store its include structure along +// with the preamble data. When we use the preamble, we can copy its +// IncludeStructure and use another collectIncludeStructureCallback() to fill +// in any non-preamble inclusions. +class IncludeStructure { +public: + std::vector<Inclusion> MainFileIncludes; + + // Return all transitively reachable files, and their minimum include depth. + // All transitive includes (absolute paths), with their minimum include depth. + // Root --> 0, #included file --> 1, etc. + // Root is clang's name for a file, which may not be absolute. + // Usually it should be SM.getFileEntryForID(SM.getMainFileID())->getName(). + llvm::StringMap<unsigned> includeDepth(llvm::StringRef Root) const; + + // This updates IncludeDepth(), but not MainFileIncludes. + void recordInclude(llvm::StringRef IncludingName, + llvm::StringRef IncludedName, + llvm::StringRef IncludedRealName); + +private: + // Identifying files in a way that persists from preamble build to subsequent + // builds is surprisingly hard. FileID is unavailable in InclusionDirective(), + // and RealPathName and UniqueID are not preseved in the preamble. + // We use the FileEntry::Name, which is stable, interned into a "file index". + // The paths we want to expose are the RealPathName, so store those too. + std::vector<std::string> RealPathNames; // In file index order. + unsigned fileIndex(llvm::StringRef Name); + llvm::StringMap<unsigned> NameToIndex; // Values are file indexes. + // Maps a file's index to that of the files it includes. + llvm::DenseMap<unsigned, SmallVector<unsigned, 8>> IncludeChildren; +}; + /// Returns a PPCallback that visits all inclusions in the main file. std::unique_ptr<PPCallbacks> -collectInclusionsInMainFileCallback(const SourceManager &SM, - std::function<void(Inclusion)> Callback); - -/// Determines the preferred way to #include a file, taking into account the -/// search path. Usually this will prefer a shorter representation like -/// 'Foo/Bar.h' over a longer one like 'Baz/include/Foo/Bar.h'. -/// -/// \param File is an absolute file path. -/// \param Inclusions Existing inclusions in the main file. -/// \param DeclaringHeader is the original header corresponding to \p -/// InsertedHeader e.g. the header that declares a symbol. -/// \param InsertedHeader The preferred header to be inserted. This could be the -/// same as DeclaringHeader but must be provided. -// \return A quoted "path" or <path>. This returns an empty string if: -/// - Either \p DeclaringHeader or \p InsertedHeader is already (directly) -/// in \p Inclusions (including those included via different paths). -/// - \p DeclaringHeader or \p InsertedHeader is the same as \p File. -llvm::Expected<std::string> calculateIncludePath( - PathRef File, StringRef BuildDir, HeaderSearch &HeaderSearchInfo, - const std::vector<Inclusion> &Inclusions, const HeaderFile &DeclaringHeader, - const HeaderFile &InsertedHeader); +collectIncludeStructureCallback(const SourceManager &SM, IncludeStructure *Out); // Calculates insertion edit for including a new header in a file. class IncludeInserter { @@ -81,16 +99,35 @@ public: void addExisting(Inclusion Inc) { Inclusions.push_back(std::move(Inc)); } - /// Returns a TextEdit that inserts a new header; if the header is not - /// inserted e.g. it's an existing header, this returns None. If any header is - /// invalid, this returns error. + /// Checks whether to add an #include of the header into \p File. + /// An #include will not be added if: + /// - Either \p DeclaringHeader or \p InsertedHeader is already (directly) + /// in \p Inclusions (including those included via different paths). + /// - \p DeclaringHeader or \p InsertedHeader is the same as \p File. /// /// \param DeclaringHeader is the original header corresponding to \p /// InsertedHeader e.g. the header that declares a symbol. /// \param InsertedHeader The preferred header to be inserted. This could be /// the same as DeclaringHeader but must be provided. - Expected<Optional<TextEdit>> insert(const HeaderFile &DeclaringHeader, - const HeaderFile &InsertedHeader) const; + bool shouldInsertInclude(const HeaderFile &DeclaringHeader, + const HeaderFile &InsertedHeader) const; + + /// Determines the preferred way to #include a file, taking into account the + /// search path. Usually this will prefer a shorter representation like + /// 'Foo/Bar.h' over a longer one like 'Baz/include/Foo/Bar.h'. + /// + /// \param DeclaringHeader is the original header corresponding to \p + /// InsertedHeader e.g. the header that declares a symbol. + /// \param InsertedHeader The preferred header to be inserted. This could be + /// the same as DeclaringHeader but must be provided. + /// + /// \return A quoted "path" or <path> to be included. + std::string calculateIncludePath(const HeaderFile &DeclaringHeader, + const HeaderFile &InsertedHeader) const; + + /// Calculates an edit that inserts \p VerbatimHeader into code. If the header + /// is already included, this returns None. + llvm::Optional<TextEdit> insert(llvm::StringRef VerbatimHeader) const; private: StringRef FileName; |