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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits