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

Reply via email to