LegalizeAdulthood updated this revision to Diff 406220.
LegalizeAdulthood added a comment.

- Use LLVM RTTI for PP node types
- Add routines to dump PP nodes


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D118711/new/

https://reviews.llvm.org/D118711

Files:
  clang-tools-extra/clang-tidy/ClangTidyCheck.cpp
  clang-tools-extra/clang-tidy/ClangTidyCheck.h
  clang-tools-extra/clang-tidy/cppcoreguidelines/MacroUsageCheck.cpp
  clang-tools-extra/clang-tidy/utils/CMakeLists.txt
  clang-tools-extra/clang-tidy/utils/PPTree.cpp
  clang-tools-extra/clang-tidy/utils/PPTree.h

Index: clang-tools-extra/clang-tidy/utils/PPTree.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/utils/PPTree.h
@@ -0,0 +1,376 @@
+//===---------- PPTree.h - clang-tidy -------------------------------------===//
+//
+// 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_TOOLS_EXTRA_CLANG_TIDY_PPTREE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PPTREE_H
+
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Token.h"
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace utils {
+
+class PPDirective {
+public:
+  enum DirectiveKind {
+    DK_Inclusion,
+    DK_Ident,
+    DK_Pragma,
+    DK_PragmaComment,
+    DK_PragmaMark,
+    DK_PragmaDetectMismatch,
+    DK_PragmaDebug,
+    DK_PragmaMessage,
+    DK_MacroDefined,
+    DK_MacroUndefined,
+    DK_If,
+    DK_Else,
+    DK_ElseIf,
+    DK_IfDef,
+    DK_IfNotDef,
+    DK_ElseIfDef,
+    DK_ElseIfNotDef,
+    DK_EndIf,
+  };
+
+  virtual ~PPDirective() = default;
+
+  DirectiveKind getKind() const { return Kind; }
+
+protected:
+  PPDirective(DirectiveKind Kind) : Kind(Kind) {}
+
+private:
+  DirectiveKind Kind;
+};
+
+using PPDirectiveStorage = std::vector<PPDirective *>;
+
+class PPDirectiveList {
+public:
+  void add(PPDirective *Dir) { Directives.emplace_back(Dir); }
+
+  ~PPDirectiveList() {
+    for (PPDirective *Dir : Directives)
+      delete Dir;
+    Directives.clear();
+  }
+
+  PPDirectiveStorage::iterator begin() { return Directives.begin(); }
+  PPDirectiveStorage::iterator end() { return Directives.end(); }
+
+  PPDirectiveStorage::const_iterator begin() const {
+    return Directives.begin();
+  }
+  PPDirectiveStorage::const_iterator end() const { return Directives.end(); }
+
+  size_t size() const { return Directives.size(); }
+
+private:
+  PPDirectiveStorage Directives;
+};
+
+class PPInclusion : public PPDirective {
+public:
+  PPInclusion(SourceLocation HashLoc, Token IncludeTok, StringRef FileName,
+              bool IsAngled, CharSourceRange FilenameRange,
+              const FileEntry *File, StringRef SearchPath,
+              StringRef RelativePath, const Module *Imported,
+              SrcMgr::CharacteristicKind FileType)
+      : PPDirective(DK_Inclusion), HashLoc(HashLoc), IncludeTok(IncludeTok),
+        FileName(FileName.str()), IsAngled(IsAngled),
+        FilenameRange(FilenameRange), File(File), SearchPath(SearchPath.str()),
+        RelativePath(RelativePath.str()), Imported(Imported),
+        FileType(FileType) {}
+
+  static bool classof(const PPDirective *D) { return D->getKind() == DK_Inclusion; }
+
+  SourceLocation HashLoc;
+  Token IncludeTok;
+  std::string FileName;
+  bool IsAngled;
+  CharSourceRange FilenameRange;
+  const FileEntry *File;
+  std::string SearchPath;
+  std::string RelativePath;
+  const Module *Imported;
+  SrcMgr::CharacteristicKind FileType;
+};
+
+class PPIdent : public PPDirective {
+public:
+  PPIdent(SourceLocation Loc, StringRef Str)
+      : PPDirective(DK_Ident), Loc(Loc), Str(Str.str()) {}
+
+  static bool classof(const PPDirective *D) { return D->getKind() == DK_Ident; }
+
+  SourceLocation Loc;
+  std::string Str;
+};
+
+class PPPragma : public PPDirective {
+public:
+  PPPragma(SourceLocation Loc, PragmaIntroducerKind Introducer)
+      : PPDirective(DK_Pragma), Loc(Loc), Introducer(Introducer) {}
+
+  static bool classof(const PPDirective *D) {
+    return D->getKind() == DK_Pragma;
+  }
+
+  SourceLocation Loc;
+  PragmaIntroducerKind Introducer;
+};
+
+class PPPragmaComment : public PPDirective {
+public:
+  PPPragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, StringRef Str)
+      : PPDirective(DK_PragmaComment), Loc(Loc), Kind(Kind), Str(Str.str()) {}
+
+  static bool classof(const PPDirective *D) {
+    return D->getKind() == DK_PragmaComment;
+  }
+
+  SourceLocation Loc;
+  const IdentifierInfo *Kind;
+  std::string Str;
+};
+
+class PPPragmaMark : public PPDirective {
+public:
+  PPPragmaMark(SourceLocation Loc, StringRef Trivia)
+      : PPDirective(DK_PragmaMark), Loc(Loc), Trivia(Trivia.str()) {}
+
+  static bool classof(const PPDirective *D) {
+    return D->getKind() == DK_PragmaMark;
+  }
+
+  SourceLocation Loc;
+  std::string Trivia;
+};
+
+class PPPragmaDetectMismatch : public PPDirective {
+public:
+  PPPragmaDetectMismatch(SourceLocation Loc, StringRef Name, StringRef Value)
+      : PPDirective(DK_PragmaDetectMismatch), Loc(Loc), Name(Name.str()),
+        Value(Value.str()) {}
+
+  static bool classof(const PPDirective *D) {
+    return D->getKind() == DK_PragmaDetectMismatch;
+  }
+
+  SourceLocation Loc;
+  std::string Name;
+  std::string Value;
+};
+
+class PPPragmaDebug : public PPDirective {
+public:
+  PPPragmaDebug(SourceLocation Loc, StringRef DebugType)
+      : PPDirective(DK_PragmaDebug), Loc(Loc), DebugType(DebugType.str()) {}
+
+  static bool classof(const PPDirective *D) {
+    return D->getKind() == DK_PragmaDebug;
+  }
+
+  SourceLocation Loc;
+  std::string DebugType;
+};
+
+class PPPragmaMessage : public PPDirective {
+public:
+  PPPragmaMessage(SourceLocation Loc, StringRef Namespace,
+                  PPCallbacks::PragmaMessageKind Kind, StringRef Str)
+      : PPDirective(DK_PragmaMessage), Loc(Loc), Namespace(Namespace.str()),
+        Kind(Kind), Str(Str.str()) {}
+
+  static bool classof(const PPDirective *D) {
+    return D->getKind() == DK_PragmaMessage;
+  }
+
+  SourceLocation Loc;
+  std::string Namespace;
+  PPCallbacks::PragmaMessageKind Kind;
+  std::string Str;
+};
+
+class PPMacroDefined : public PPDirective {
+public:
+  PPMacroDefined(const Token &MacroNameTok, const MacroDirective *MD)
+      : PPDirective(DK_MacroDefined), Name(MacroNameTok), MD(MD) {}
+
+  static bool classof(const PPDirective *D) {
+    return D->getKind() == DK_MacroDefined;
+  }
+
+  Token Name;
+  const MacroDirective *MD;
+};
+
+class PPMacroUndefined : public PPDirective {
+public:
+  PPMacroUndefined(Token Name, const MacroDefinition *MD,
+                   const MacroDirective *Undef)
+      : PPDirective(DK_MacroUndefined), Name(Name), MD(MD), Undef(Undef) {}
+
+  static bool classof(const PPDirective *D) {
+    return D->getKind() == DK_MacroUndefined;
+  }
+
+  Token Name;
+  const MacroDefinition *MD;
+  const MacroDirective *Undef;
+};
+
+class PPIf : public PPDirective {
+public:
+  PPIf(SourceLocation Loc, SourceRange ConditionRange,
+       PPCallbacks::ConditionValueKind ConditionValue)
+      : PPDirective(DK_If), Loc(Loc), ConditionRange(ConditionRange),
+        ConditionValue(ConditionValue) {}
+
+  static bool classof(const PPDirective *D) { return D->getKind() == DK_If; }
+
+  SourceLocation Loc;
+  SourceRange ConditionRange;
+  PPCallbacks::ConditionValueKind ConditionValue;
+  PPDirectiveList Directives;
+};
+
+class PPElse : public PPDirective {
+public:
+  PPElse(SourceLocation Loc, SourceLocation IfLoc)
+      : PPDirective(DK_Else), Loc(Loc), IfLoc(IfLoc) {}
+
+  static bool classof(const PPDirective *D) { return D->getKind() == DK_Else; }
+
+  SourceLocation Loc;
+  SourceLocation IfLoc;
+  PPDirectiveList Directives;
+};
+
+class PPElseIf : public PPDirective {
+public:
+  PPElseIf(SourceLocation Loc, SourceRange ConditionRange,
+           PPCallbacks::ConditionValueKind ConditionValue, SourceLocation IfLoc)
+      : PPDirective(DK_ElseIf), Loc(Loc), ConditionRange(ConditionRange),
+        ConditionValue(ConditionValue), IfLoc(IfLoc) {}
+
+  static bool classof(const PPDirective *D) {
+    return D->getKind() == DK_ElseIf;
+  }
+
+  SourceLocation Loc;
+  SourceRange ConditionRange;
+  PPCallbacks::ConditionValueKind ConditionValue;
+  SourceLocation IfLoc;
+  PPDirectiveList Directives;
+};
+
+class PPIfDef : public PPDirective {
+public:
+  PPIfDef(SourceLocation Loc, const Token &MacroNameTok,
+          const MacroDefinition &MD)
+      : PPDirective(DK_IfDef), Loc(Loc), Name(MacroNameTok), MD(&MD) {}
+
+  static bool classof(const PPDirective *D) { return D->getKind() == DK_IfDef; }
+
+  SourceLocation Loc;
+  Token Name;
+  const MacroDefinition *MD;
+  PPDirectiveList Directives;
+};
+
+class PPIfNotDef : public PPDirective {
+public:
+  PPIfNotDef(SourceLocation Loc, const Token &MacroNameTok,
+             const MacroDefinition &MD)
+      : PPDirective(DK_IfNotDef), Loc(Loc), Name(MacroNameTok), MD(&MD) {}
+
+  static bool classof(const PPDirective *D) {
+    return D->getKind() == DK_IfNotDef;
+  }
+
+  SourceLocation Loc;
+  Token Name;
+  const MacroDefinition *MD;
+  PPDirectiveList Directives;
+};
+
+class PPElseIfDef : public PPDirective {
+public:
+  PPElseIfDef(SourceLocation Loc, const Token &MacroNameTok,
+              const MacroDefinition &MD)
+      : PPDirective(DK_ElseIfDef), Loc(Loc), Name(MacroNameTok), MD(&MD) {}
+
+  static bool classof(const PPDirective *D) {
+    return D->getKind() == DK_ElseIfDef;
+  }
+
+  SourceLocation Loc;
+  Token Name;
+  const MacroDefinition *MD;
+  PPDirectiveList Directives;
+};
+
+class PPElseIfNotDef : public PPDirective {
+public:
+  PPElseIfNotDef(SourceLocation Loc, const Token &MacroNameTok,
+                 const MacroDefinition &MD)
+      : PPDirective(DK_ElseIfNotDef), Loc(Loc), Name(MacroNameTok), MD(&MD) {}
+
+  static bool classof(const PPDirective *D) {
+    return D->getKind() == DK_ElseIfNotDef;
+  }
+
+  SourceLocation Loc;
+  Token Name;
+  const MacroDefinition *MD;
+  PPDirectiveList Directives;
+};
+
+class PPEndIf : public PPDirective {
+public:
+  PPEndIf(SourceLocation Loc, SourceLocation IfLoc)
+      : PPDirective(DK_EndIf), Loc(Loc), IfLoc(IfLoc) {}
+
+  static bool classof(const PPDirective *D) { return D->getKind() == DK_EndIf; }
+
+  SourceLocation Loc;
+  SourceLocation IfLoc;
+};
+
+struct PPTree {
+  PPDirectiveList Directives;
+};
+
+class PPTreeConsumer {
+public:
+  virtual ~PPTreeConsumer() = default;
+
+  virtual void endOfMainFile(const utils::PPTree *Tree) = 0;
+};
+
+class PPTreeBuilder {
+public:
+  PPTreeBuilder(PPTreeConsumer *Callback, Preprocessor *PP,
+                const SourceManager &SM, const LangOptions &LangOpts);
+
+private:
+  Preprocessor *PP;
+  PPTreeConsumer *Callback;
+  const SourceManager &SM;
+  const LangOptions &LangOpts;
+};
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PPTREE_H
Index: clang-tools-extra/clang-tidy/utils/PPTree.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/utils/PPTree.cpp
@@ -0,0 +1,257 @@
+//===-------- PPTree.cpp - clang-tidy -------------------------------------===//
+//
+// 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 "PPTree.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/Token.h"
+#include <memory>
+
+namespace clang {
+namespace tidy {
+namespace utils {
+namespace {
+
+class PPTreeBuilderCallbacks : public PPCallbacks {
+public:
+  PPTreeBuilderCallbacks(PPTreeConsumer *Callback, const SourceManager &SM,
+                         const LangOptions &LangOpts)
+      : Callback(Callback), SM(SM), LangOpts(LangOpts) {}
+
+  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+                          StringRef FileName, bool IsAngled,
+                          CharSourceRange FilenameRange, const FileEntry *File,
+                          StringRef SearchPath, StringRef RelativePath,
+                          const Module *Imported,
+                          SrcMgr::CharacteristicKind FileType) override;
+  void EndOfMainFile() override;
+  void Ident(SourceLocation Loc, StringRef Str) override;
+  void PragmaDirective(SourceLocation Loc,
+                       PragmaIntroducerKind Introducer) override;
+  void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind,
+                     StringRef Str) override;
+  void PragmaMark(SourceLocation Loc, StringRef Trivia) override;
+  void PragmaDetectMismatch(SourceLocation Loc, StringRef Name,
+                            StringRef Value) override;
+  void PragmaDebug(SourceLocation Loc, StringRef DebugType) override;
+  void PragmaMessage(SourceLocation Loc, StringRef Namespace,
+                     PragmaMessageKind Kind, StringRef Str) override;
+
+  void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
+                    SourceRange Range, const MacroArgs *Args) override;
+  void MacroDefined(const Token &MacroNameTok,
+                    const MacroDirective *MD) override;
+  void MacroUndefined(const Token &MacroNameTok, const MacroDefinition &MD,
+                      const MacroDirective *Undef) override;
+  void Defined(const Token &MacroNameTok, const MacroDefinition &MD,
+               SourceRange Range) override;
+
+  void If(SourceLocation Loc, SourceRange ConditionRange,
+          ConditionValueKind ConditionValue) override;
+  void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
+             const MacroDefinition &MD) override;
+  void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
+              const MacroDefinition &MD) override;
+  void Else(SourceLocation Loc, SourceLocation IfLoc) override;
+  void Elif(SourceLocation Loc, SourceRange ConditionRange,
+            ConditionValueKind ConditionValue, SourceLocation IfLoc) override;
+  void Elifdef(SourceLocation Loc, const Token &MacroNameTok,
+               const MacroDefinition &MD) override;
+  void Elifndef(SourceLocation Loc, const Token &MacroNameTok,
+                const MacroDefinition &MD) override;
+  void Endif(SourceLocation Loc, SourceLocation IfLoc) override;
+  void pushDirectiveStack(PPDirectiveList *List);
+
+private:
+  void popDirectiveStack();
+
+  PPTreeConsumer *Callback;
+  const SourceManager &SM;
+  const LangOptions &LangOpts;
+  PPTree Tree;
+  std::vector<PPDirectiveList *> DirectiveStack{&Tree.Directives};
+  PPDirectiveList *Directives = DirectiveStack.back();
+};
+
+void PPTreeBuilderCallbacks::InclusionDirective(
+    SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
+    bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
+    StringRef SearchPath, StringRef RelativePath, const Module *Imported,
+    SrcMgr::CharacteristicKind FileType) {
+  auto Directive{std::make_unique<PPInclusion>(
+      HashLoc, IncludeTok, FileName, IsAngled, FilenameRange, File, SearchPath,
+      RelativePath, Imported, FileType)};
+  Directives->add(Directive.release());
+}
+
+void PPTreeBuilderCallbacks::EndOfMainFile() {
+  Callback->endOfMainFile(&Tree);
+}
+
+void PPTreeBuilderCallbacks::Ident(SourceLocation Loc, StringRef Str) {
+  auto Directive{std::make_unique<PPIdent>(Loc, Str)};
+  Directives->add(Directive.release());
+}
+
+void PPTreeBuilderCallbacks::PragmaDirective(SourceLocation Loc,
+                                             PragmaIntroducerKind Introducer) {
+  auto Directive{std::make_unique<PPPragma>(Loc, Introducer)};
+  Directives->add(Directive.release());
+}
+
+void PPTreeBuilderCallbacks::PragmaComment(SourceLocation Loc,
+                                           const IdentifierInfo *Kind,
+                                           StringRef Str) {
+  auto Directive{std::make_unique<PPPragmaComment>(Loc, Kind, Str)};
+  Directives->add(Directive.release());
+}
+
+void PPTreeBuilderCallbacks::PragmaMark(SourceLocation Loc, StringRef Trivia) {
+  auto Directive{std::make_unique<PPPragmaMark>(Loc, Trivia)};
+  Directives->add(Directive.release());
+}
+
+void PPTreeBuilderCallbacks::PragmaDetectMismatch(SourceLocation Loc,
+                                                  StringRef Name,
+                                                  StringRef Value) {
+  auto Directive{std::make_unique<PPPragmaDetectMismatch>(Loc, Name, Value)};
+  Directives->add(Directive.release());
+}
+
+void PPTreeBuilderCallbacks::PragmaDebug(SourceLocation Loc,
+                                         StringRef DebugType) {
+  auto Directive{std::make_unique<PPPragmaDebug>(Loc, DebugType)};
+  Directives->add(Directive.release());
+}
+
+void PPTreeBuilderCallbacks::PragmaMessage(SourceLocation Loc,
+                                           StringRef Namespace,
+                                           PragmaMessageKind Kind,
+                                           StringRef Str) {
+  auto Directive{std::make_unique<PPPragmaMessage>(Loc, Namespace, Kind, Str)};
+  Directives->add(Directive.release());
+}
+
+void PPTreeBuilderCallbacks::MacroExpands(const Token &MacroNameTok,
+                                          const MacroDefinition &MD,
+                                          SourceRange Range,
+                                          const MacroArgs *Args) {
+}
+
+void PPTreeBuilderCallbacks::MacroDefined(const Token &MacroNameTok,
+                                          const MacroDirective *MD) {
+  auto Directive{std::make_unique<PPMacroDefined>(MacroNameTok, MD)};
+  Directives->add(Directive.release());
+}
+
+void PPTreeBuilderCallbacks::MacroUndefined(const Token &MacroNameTok,
+                                            const MacroDefinition &MD,
+                                            const MacroDirective *Undef) {
+  auto Directive{std::make_unique<PPMacroUndefined>(MacroNameTok, &MD, Undef)};
+  Directives->add(Directive.release());
+}
+
+void PPTreeBuilderCallbacks::Defined(const Token &MacroNameTok,
+                                     const MacroDefinition &MD,
+                                     SourceRange Range) {
+}
+
+void PPTreeBuilderCallbacks::If(SourceLocation Loc, SourceRange ConditionRange,
+                                ConditionValueKind ConditionValue) {
+  auto Directive{std::make_unique<PPIf>(Loc, ConditionRange, ConditionValue)};
+  PPDirectiveList *NewContext = &Directive->Directives;
+  Directives->add(Directive.release());
+  pushDirectiveStack(NewContext);
+}
+
+void PPTreeBuilderCallbacks::Ifdef(SourceLocation Loc,
+                                   const Token &MacroNameTok,
+                                   const MacroDefinition &MD) {
+  auto Directive{std::make_unique<PPIfDef>(Loc, MacroNameTok, MD)};
+  PPDirectiveList *NewContext = &Directive->Directives;
+  Directives->add(Directive.release());
+  pushDirectiveStack(NewContext);
+}
+
+void PPTreeBuilderCallbacks::Ifndef(SourceLocation Loc,
+                                    const Token &MacroNameTok,
+                                    const MacroDefinition &MD) {
+  auto Directive{std::make_unique<PPIfNotDef>(Loc, MacroNameTok, MD)};
+  PPDirectiveList *NewContext = &Directive->Directives;
+  Directives->add(Directive.release());
+  pushDirectiveStack(NewContext);
+}
+
+void PPTreeBuilderCallbacks::Else(SourceLocation Loc, SourceLocation IfLoc) {
+  auto Directive{std::make_unique<PPElse>(Loc, IfLoc)};
+  PPDirectiveList *NewContext = &Directive->Directives;
+  popDirectiveStack();
+  Directives->add(Directive.release());
+  pushDirectiveStack(NewContext);
+}
+
+void PPTreeBuilderCallbacks::Elif(SourceLocation Loc,
+                                  SourceRange ConditionRange,
+                                  ConditionValueKind ConditionValue,
+                                  SourceLocation IfLoc) {
+  auto Directive{std::make_unique<PPElseIf>(Loc, ConditionRange, ConditionValue, IfLoc)};
+  PPDirectiveList *NewContext = &Directive->Directives;
+  popDirectiveStack();
+  Directives->add(Directive.release());
+  pushDirectiveStack(NewContext);
+}
+
+void PPTreeBuilderCallbacks::Elifdef(SourceLocation Loc,
+                                     const Token &MacroNameTok,
+                                     const MacroDefinition &MD) {
+  auto Directive{std::make_unique<PPElseIfDef>(Loc, MacroNameTok, MD)};
+  PPDirectiveList *NewContext = &Directive->Directives;
+  popDirectiveStack();
+  Directives->add(Directive.release());
+  pushDirectiveStack(NewContext);
+}
+
+void PPTreeBuilderCallbacks::Elifndef(SourceLocation Loc,
+                                      const Token &MacroNameTok,
+                                      const MacroDefinition &MD) {
+  auto Directive{std::make_unique<PPElseIfNotDef>(Loc, MacroNameTok, MD)};
+  PPDirectiveList *NewContext = &Directive->Directives;
+  popDirectiveStack();
+  Directives->add(Directive.release());
+  pushDirectiveStack(NewContext);
+}
+
+void PPTreeBuilderCallbacks::Endif(SourceLocation Loc, SourceLocation IfLoc) {
+  popDirectiveStack();
+  auto Directive{std::make_unique<PPEndIf>(Loc, IfLoc)};
+  Directives->add(Directive.release());
+}
+
+void PPTreeBuilderCallbacks::pushDirectiveStack(PPDirectiveList *List) {
+  DirectiveStack.push_back(List);
+  Directives = DirectiveStack.back();
+}
+
+void PPTreeBuilderCallbacks::popDirectiveStack() {
+  assert(DirectiveStack.size() > 1);
+  DirectiveStack.pop_back();
+  Directives = DirectiveStack.back();
+}
+
+} // namespace
+
+PPTreeBuilder::PPTreeBuilder(PPTreeConsumer *Callback, Preprocessor *PP,
+                             const SourceManager &SM, const LangOptions &LangOpts)
+    : PP(PP), Callback(Callback), SM(SM), LangOpts(LangOpts) {
+  PP->addPPCallbacks(
+      std::make_unique<PPTreeBuilderCallbacks>(Callback, SM, LangOpts));
+}
+
+} // namespace utils
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/utils/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/utils/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/utils/CMakeLists.txt
@@ -17,6 +17,7 @@
   LexerUtils.cpp
   NamespaceAliaser.cpp
   OptionsUtils.cpp
+  PPTree.cpp
   RenamerClangTidyCheck.cpp
   TransformerClangTidyCheck.cpp
   TypeTraits.cpp
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/MacroUsageCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/cppcoreguidelines/MacroUsageCheck.cpp
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/MacroUsageCheck.cpp
@@ -74,6 +74,7 @@
 void MacroUsageCheck::registerPPCallbacks(const SourceManager &SM,
                                           Preprocessor *PP,
                                           Preprocessor *ModuleExpanderPP) {
+  ClangTidyCheck::registerPPCallbacks(SM, PP, ModuleExpanderPP);
   PP->addPPCallbacks(std::make_unique<MacroUsageCallbacks>(
       this, SM, AllowedRegexp, CheckCapsOnly, IgnoreCommandLineMacros));
 }
Index: clang-tools-extra/clang-tidy/ClangTidyCheck.h
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidyCheck.h
+++ clang-tools-extra/clang-tidy/ClangTidyCheck.h
@@ -88,7 +88,7 @@
   ///    When modules are not enabled ModuleExpanderPP just points to the real
   ///    preprocessor.
   virtual void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
-                                   Preprocessor *ModuleExpanderPP) {}
+                                   Preprocessor *ModuleExpanderPP);
 
   /// Override this to register AST matchers with \p Finder.
   ///
Index: clang-tools-extra/clang-tidy/ClangTidyCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidyCheck.cpp
+++ clang-tools-extra/clang-tidy/ClangTidyCheck.cpp
@@ -7,14 +7,230 @@
 //===----------------------------------------------------------------------===//
 
 #include "ClangTidyCheck.h"
+#include "utils/PPTree.h"
+#include "clang/Lex/MacroInfo.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/YAMLParser.h"
 
+#include <iostream>
+
 namespace clang {
 namespace tidy {
 
+using namespace utils;
+
+static size_t IndentLevel = 0;
+
+static std::string printToString(const SourceManager &SM, CharSourceRange R) {
+  return R.getBegin().printToString(SM) + ", " + R.getEnd().printToString(SM);
+}
+
+static std::string indent() { return std::string(IndentLevel * 2, '.'); }
+
+static auto &errs() { return llvm::errs() << indent(); }
+
+static void dumpDirectives(const SourceManager &SM,
+                           const PPDirectiveList &Directives);
+
+static void dumpInclusion(const SourceManager &SM, const PPInclusion *D) {
+  errs() << "Inclusion\n"
+         << indent() << D->HashLoc.printToString(SM) << '\n'
+         << indent() << D->IncludeTok.getIdentifierInfo()->getName().str()
+         << '\n'
+         << indent() << D->FileName << '\n'
+         << indent() << (D->IsAngled ? "Angled\n" : "") << indent()
+         << printToString(SM, D->FilenameRange) << '\n'
+         << indent() << D->File->getDir()->getName().str() << '\n'
+         << indent() << D->SearchPath << '\n'
+         << indent() << D->RelativePath << '\n'
+         << indent() << (D->Imported != nullptr ? "<Imported>\n" : "")
+         << indent() << "FileType " << indent() << D->FileType << '\n';
+}
+static void dumpIdent(const SourceManager &SM, const PPIdent *D) {
+  errs() << "Ident\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->Str << '\n';
+}
+static void dumpPragma(const SourceManager &SM, const PPPragma *D) {
+  errs() << "Pragma\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << "Introducer " << D->Introducer << '\n';
+}
+static void dumpPragmaComment(const SourceManager &SM,
+                              const PPPragmaComment *D) {
+  errs() << "Comment\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->Kind->getName().str() << '\n'
+         << indent() << D->Str << '\n';
+}
+static void dumpPragmaMark(const SourceManager &SM, const PPPragmaMark *D) {
+  errs() << "Mark\n"
+         << D->Loc.printToString(SM) << '\n'
+         << indent() << D->Trivia << '\n';
+}
+static void dumpPragmaDetectMismatch(const SourceManager &SM,
+                                     const PPPragmaDetectMismatch *D) {
+  errs() << "Detect Mismatch\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->Name << '\n'
+         << indent() << D->Value << '\n';
+}
+static void dumpPragmaDebug(const SourceManager &SM, const PPPragmaDebug *D) {
+  errs() << "Debug\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->DebugType << '\n';
+}
+static void dumpPragmaMessage(const SourceManager &SM,
+                              const PPPragmaMessage *D) {
+  errs() << "Message\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->Namespace << '\n'
+         << indent() << D->Kind << '\n'
+         << indent() << D->Str << '\n';
+}
+static void dumpMacroDefined(const SourceManager &SM, const PPMacroDefined *D) {
+  errs() << "Macro Defined\n"
+         << indent() << D->Name.getIdentifierInfo()->getName().str() << '\n';
+}
+static void dumpMacroUndefined(const SourceManager &SM,
+                               const PPMacroUndefined *D) {
+  errs() << "Macro Undefined\n"
+         << indent() << D->Name.getIdentifierInfo()->getName().str() << '\n';
+}
+static void dumpIf(const SourceManager &SM, const PPIf *D) {
+  errs() << "If\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->ConditionRange.getBegin().printToString(SM) << ", "
+         << D->ConditionRange.getEnd().printToString(SM) << '\n'
+         << indent() << D->ConditionValue << '\n';
+  ++IndentLevel;
+  dumpDirectives(SM, D->Directives);
+  --IndentLevel;
+}
+static void dumpElse(const SourceManager &SM, const PPElse *D) {
+  errs() << "Else\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->IfLoc.printToString(SM) << '\n';
+  ++IndentLevel;
+  dumpDirectives(SM, D->Directives);
+  --IndentLevel;
+}
+static void dumpElseIf(const SourceManager &SM, const PPElseIf *D) {
+  errs() << "ElseIf\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->ConditionRange.getBegin().printToString(SM) << ", "
+         << D->ConditionRange.getEnd().printToString(SM) << '\n'
+         << indent() << D->ConditionValue << '\n'
+         << indent() << D->IfLoc.printToString(SM) << '\n';
+  ++IndentLevel;
+  dumpDirectives(SM, D->Directives);
+  --IndentLevel;
+}
+static void dumpIfDef(const SourceManager &SM, const PPIfDef *D) {
+  errs() << "IfDef\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->Name.getIdentifierInfo()->getName().str() << '\n';
+  ++IndentLevel;
+  dumpDirectives(SM, D->Directives);
+  --IndentLevel;
+}
+static void dumpIfNotDef(const SourceManager &SM, const PPIfNotDef *D) {
+  errs() << "IfNotDef\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->Name.getIdentifierInfo()->getName().str() << '\n';
+  ++IndentLevel;
+  dumpDirectives(SM, D->Directives);
+  --IndentLevel;
+}
+static void dumpElseIfDef(const SourceManager &SM, const PPElseIfDef *D) {
+  errs() << "ElseIfDef\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->Name.getIdentifierInfo()->getName().str() << '\n';
+  ++IndentLevel;
+  dumpDirectives(SM, D->Directives);
+  --IndentLevel;
+}
+static void dumpElseIfNotDef(const SourceManager &SM, const PPElseIfNotDef *D) {
+  errs() << "ElseIfNotDef\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->Name.getIdentifierInfo()->getName().str() << '\n';
+  ++IndentLevel;
+  dumpDirectives(SM, D->Directives);
+  --IndentLevel;
+}
+static void dumpEndIf(const SourceManager &SM, const PPEndIf *D) {
+  errs() << "EndIf\n"
+         << indent() << D->Loc.printToString(SM) << '\n'
+         << indent() << D->IfLoc.printToString(SM) << '\n';
+}
+
+static void dumpDirectives(const SourceManager &SM,
+                           const PPDirectiveList &Directives) {
+  for (const PPDirective *Directive : Directives) {
+    if (const PPMacroDefined *Def = dyn_cast<PPMacroDefined>(Directive))
+      dumpMacroDefined(SM, Def);
+    else if (const PPInclusion *I = dyn_cast<PPInclusion>(Directive))
+      dumpInclusion(SM, I);
+    else if (const PPIdent *ID = dyn_cast<PPIdent>(Directive))
+      dumpIdent(SM, ID);
+    else if (const PPPragma *P = dyn_cast<PPPragma>(Directive))
+      dumpPragma(SM, P);
+    else if (const PPPragmaComment *C = dyn_cast<PPPragmaComment>(Directive))
+      dumpPragmaComment(SM, C);
+    else if (const PPPragmaMark *M = dyn_cast<PPPragmaMark>(Directive))
+      dumpPragmaMark(SM, M);
+    else if (const PPPragmaDetectMismatch *MM =
+                 dyn_cast<PPPragmaDetectMismatch>(Directive))
+      dumpPragmaDetectMismatch(SM, MM);
+    else if (const PPPragmaDebug *Dbg = dyn_cast<PPPragmaDebug>(Directive))
+      dumpPragmaDebug(SM, Dbg);
+    else if (const PPPragmaMessage *Msg = dyn_cast<PPPragmaMessage>(Directive))
+      dumpPragmaMessage(SM, Msg);
+    else if (const PPMacroUndefined *Undef =
+                 dyn_cast<PPMacroUndefined>(Directive))
+      dumpMacroUndefined(SM, Undef);
+    else if (const PPIf *If = dyn_cast<PPIf>(Directive))
+      dumpIf(SM, If);
+    else if (const PPElse *Else = dyn_cast<PPElse>(Directive))
+      dumpElse(SM, Else);
+    else if (const PPElseIf *ElseIf = dyn_cast<PPElseIf>(Directive))
+      dumpElseIf(SM, ElseIf);
+    else if (const PPIfDef *IfDef = dyn_cast<PPIfDef>(Directive))
+      dumpIfDef(SM, IfDef);
+    else if (const PPIfNotDef *IfNotDef = dyn_cast<PPIfNotDef>(Directive))
+      dumpIfNotDef(SM, IfNotDef);
+    else if (const PPElseIfDef *ElseIfDef = dyn_cast<PPElseIfDef>(Directive))
+      dumpElseIfDef(SM, ElseIfDef);
+    else if (const PPElseIfNotDef *ElseIfNotDef =
+                 dyn_cast<PPElseIfNotDef>(Directive))
+      dumpElseIfNotDef(SM, ElseIfNotDef);
+    else if (const PPEndIf *EndIf = dyn_cast<PPEndIf>(Directive))
+      dumpEndIf(SM, EndIf);
+  }
+}
+
+namespace {
+
+class CheckPPTreeConsumer : public PPTreeConsumer {
+public:
+  CheckPPTreeConsumer(ClangTidyCheck *Check) : Check(Check) {}
+  void endOfMainFile(const PPTree *Tree) override {
+    llvm::errs() << "End of main file: " << Tree->Directives.size()
+                 << " directives.\n";
+    dumpDirectives(*SM, Tree->Directives);
+  }
+
+  ClangTidyCheck *Check;
+  const SourceManager *SM{};
+};
+
+} // namespace
+
+static std::unique_ptr<CheckPPTreeConsumer> TreeConsumer;
+static std::unique_ptr<PPTreeBuilder> TreeBuilder;
+
 ClangTidyCheck::ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context)
     : CheckName(CheckName), Context(Context),
       Options(CheckName, Context->getOptions().CheckOptions, Context) {
@@ -22,6 +238,14 @@
   assert(!CheckName.empty());
 }
 
+void ClangTidyCheck::registerPPCallbacks(const SourceManager &SM,
+                                         Preprocessor *PP,
+                                         Preprocessor *ModuleExpanderPP) {
+  TreeConsumer.reset(new CheckPPTreeConsumer(this));
+  TreeBuilder.reset(
+      new PPTreeBuilder(TreeConsumer.get(), PP, SM, getLangOpts()));
+}
+
 DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message,
                                        DiagnosticIDs::Level Level) {
   return Context->diag(CheckName, Loc, Message, Level);
@@ -60,8 +284,8 @@
 }
 
 static ClangTidyOptions::OptionMap::const_iterator
-findPriorityOption(const ClangTidyOptions::OptionMap &Options, StringRef NamePrefix,
-          StringRef LocalName) {
+findPriorityOption(const ClangTidyOptions::OptionMap &Options,
+                   StringRef NamePrefix, StringRef LocalName) {
   auto IterLocal = Options.find((NamePrefix + LocalName).str());
   auto IterGlobal = Options.find(LocalName.str());
   if (IterLocal == Options.end())
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to