hokein created this revision. hokein added reviewers: sammccall, kadircet. Herald added a project: All. hokein requested review of this revision. Herald added a project: clang-tools-extra.
PragmaIncludes captures the progma-based header-mapping information, it is used in the "Location => Header" step to determine the final spelling header for a symbol (rather than the header directive). Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D136071 Files: clang-tools-extra/include-cleaner/include/clang-include-cleaner/Hooks.h clang-tools-extra/include-cleaner/lib/Hooks.cpp
Index: clang-tools-extra/include-cleaner/lib/Hooks.cpp =================================================================== --- clang-tools-extra/include-cleaner/lib/Hooks.cpp +++ clang-tools-extra/include-cleaner/lib/Hooks.cpp @@ -11,9 +11,73 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclGroup.h" #include "clang/Basic/SourceManager.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" +#include <memory> +#include <type_traits> namespace clang::include_cleaner { +// FIXME: this is a mirror of clang::clangd::parseIWYUPragma, share the code? +static llvm::Optional<StringRef> parseIWYUPragma(const char *Text) { + constexpr llvm::StringLiteral IWYUPragma = "// IWYU pragma: "; + if (strncmp(Text, IWYUPragma.data(), IWYUPragma.size())) + return llvm::None; + Text += IWYUPragma.size(); + const char *End = Text; + while (*End != 0 && *End != '\n') + ++End; + return StringRef(Text, End - Text); +} + +class PragmaIncludes::RecordPragma : public PPCallbacks, public CommentHandler { +public: + RecordPragma(PragmaIncludes *Out) : Out(Out) {} + + bool HandleComment(Preprocessor &PP, SourceRange Range) override { + bool Invalid = false; + auto Pragma = parseIWYUPragma( + PP.getSourceManager().getCharacterData(Range.getBegin(), &Invalid)); + if (!Pragma || Invalid) + return false; + + if (Pragma->consume_front("private, include ")) { + auto &SM = PP.getSourceManager(); + // We always insert using the spelling from the pragma. + if (auto *FE = SM.getFileEntryForID(SM.getFileID(Range.getBegin()))) + Out->IWYUPrivate.insert( + {FE->getLastRef().getUniqueID(), + Pragma->startswith("<") || Pragma->startswith("\"") + ? Pragma->str() + : ("\"" + *Pragma + "\"").str()}); + return false; + } + return false; + } + +private: + PragmaIncludes *Out; +}; + +void PragmaIncludes::record(const CompilerInstance &CI) { + auto Record = std::make_unique<RecordPragma>(this); + CI.getPreprocessor().addCommentHandler(Record.get()); + CI.getPreprocessor().addPPCallbacks(std::move(Record)); +} + +bool PragmaIncludes::shouldKeep(FileEntryRef F) const { + auto It = ShouldKeep.find(F.getUniqueID()); + return It != ShouldKeep.end(); +} + +llvm::StringRef PragmaIncludes::getMapping(FileEntryRef F) const { + auto It = IWYUPrivate.find(F.getUniqueID()); + if (It == IWYUPrivate.end()) + return ""; + return It->getSecond(); +} + std::unique_ptr<ASTConsumer> RecordedAST::record() { class Recorder : public ASTConsumer { RecordedAST *Out; Index: clang-tools-extra/include-cleaner/include/clang-include-cleaner/Hooks.h =================================================================== --- clang-tools-extra/include-cleaner/include/clang-include-cleaner/Hooks.h +++ clang-tools-extra/include-cleaner/include/clang-include-cleaner/Hooks.h @@ -17,6 +17,8 @@ #ifndef CLANG_INCLUDE_CLEANER_HOOKS_H #define CLANG_INCLUDE_CLEANER_HOOKS_H +#include "clang/Basic/FileEntry.h" +#include "llvm/ADT/DenseSet.h" #include <memory> #include <vector> @@ -24,8 +26,40 @@ class ASTConsumer; class ASTContext; class Decl; +class CompilerInstance; + namespace include_cleaner { +// Captures #include mapping information. It analyses IWYU Pragma comments and +// other use_instead mechanisms (clang use_instead pragma) on included files. +// +// Used in the "Location => Header" analysis step to determine the final +// spelling header rather than the header directly defines the symbol. +class PragmaIncludes { +public: + // Installs an analysing PPCallback and CommentHandler and populates results + // to the structure. + void record(const CompilerInstance &CI); + + bool shouldKeep(FileEntryRef File) const; + // Returns the mapping include for the given physical header file. + // Returns "" if there is no mapping. + llvm::StringRef getMapping(FileEntryRef File) const; + + class RecordPragma; + +private: + // Main file headers that should be kept, decorated by "IWYU pragma: keep". + llvm::DenseSet<llvm::sys::fs::UniqueID> ShouldKeep; // FIXME: implement + + // Header mapping by IWYU private pragma. + llvm::DenseMap<llvm::sys::fs::UniqueID, std::string /*VerbatimSpelling*/> + IWYUPrivate; + + // FIXME: add other IWYU supports (export etc) + // FIXME: add support for clang use_instead progma +}; + // Contains recorded parser events relevant to include-cleaner. struct RecordedAST { // The consumer (when installed into clang) tracks declarations in this.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits