Index: clang-tools-extra/clang-tidy/ClangTidyCheck.h =================================================================== --- clang-tools-extra/clang-tidy/ClangTidyCheck.h +++ clang-tools-extra/clang-tidy/ClangTidyCheck.h @@ -89,7 +89,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 @@ -11,10 +11,26 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/YAMLParser.h" +#include "utils/PPTree.h" + +#include namespace clang { namespace tidy { +namespace { +class CheckPPTreeConsumer : public utils::PPTreeConsumer { +public: + void endOfMainFile(const utils::PPTree *Tree) override { + std::cout << "End of main file: " << Tree->Directives.size() << " directives.\n"; + } +}; + +} + +CheckPPTreeConsumer TreeConsumer; +static std::unique_ptr TreeBuilder; + ClangTidyCheck::ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context) : CheckName(CheckName), Context(Context), Options(CheckName, Context->getOptions().CheckOptions, Context) { @@ -22,6 +38,11 @@ assert(!CheckName.empty()); } +void ClangTidyCheck::registerPPCallbacks(const SourceManager &SM, + Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + TreeBuilder.reset(new utils::PPTreeBuilder(&TreeConsumer, PP, SM, getLangOpts())); +} + DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message, DiagnosticIDs::Level Level) { return Context->diag(CheckName, Loc, Message, Level); 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( this, SM, AllowedRegexp, CheckCapsOnly, IgnoreCommandLineMacros)); } 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/utils/PPTree.h =================================================================== --- /dev/null +++ clang-tools-extra/clang-tidy/utils/PPTree.h @@ -0,0 +1,258 @@ +//===---------- 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 + +namespace clang { +namespace tidy { +namespace utils { + +struct PPDirective { + virtual ~PPDirective() = default; +}; + +using PPDirectiveStorage = std::vector; + +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; +}; + +struct PPInclusion : PPDirective { + PPInclusion(SourceLocation HashLoc, Token IncludeTok, StringRef FileName, + bool IsAngled, CharSourceRange FilenameRange, + const FileEntry *File, StringRef SearchPath, + StringRef RelativePath, const Module *Imported, + SrcMgr::CharacteristicKind FileType) + : HashLoc(HashLoc), IncludeTok(IncludeTok), FileName(FileName.str()), + IsAngled(IsAngled), FilenameRange(FilenameRange), File(File), + SearchPath(SearchPath.str()), RelativePath(RelativePath.str()), + Imported(Imported), FileType(FileType) {} + + 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; +}; + +struct PPIdent : PPDirective { + PPIdent(SourceLocation Loc, StringRef Str) : Loc(Loc), Str(Str.str()) {} + + SourceLocation Loc; + std::string Str; +}; + +struct PPPragma : PPDirective { + PPPragma(SourceLocation Loc, PragmaIntroducerKind Introducer) + : Loc(Loc), Introducer(Introducer) {} + + SourceLocation Loc; + PragmaIntroducerKind Introducer; +}; + +struct PPPragmaComment : PPDirective { + PPPragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + StringRef Str) : Loc(Loc), Kind(Kind), Str(Str.str()) {} + + SourceLocation Loc; + const IdentifierInfo *Kind; + std::string Str; +}; + +struct PPPragmaMark : PPDirective { + PPPragmaMark(SourceLocation Loc, StringRef Trivia) + : Loc(Loc), Trivia(Trivia.str()) {} + + SourceLocation Loc; + std::string Trivia; +}; + +struct PPPragmaDetectMismatch : PPDirective { + PPPragmaDetectMismatch(SourceLocation Loc, StringRef Name, StringRef Value) + : Loc(Loc), Name(Name.str()), Value(Value.str()) {} + + SourceLocation Loc; + std::string Name; + std::string Value; +}; + +struct PPPragmaDebug : PPDirective { + PPPragmaDebug(SourceLocation Loc, StringRef DebugType) + : Loc(Loc), DebugType(DebugType.str()) {} + + SourceLocation Loc; + std::string DebugType; +}; + +struct PPPragmaMessage : PPDirective { + PPPragmaMessage(SourceLocation Loc, StringRef Namespace, + PPCallbacks::PragmaMessageKind Kind, StringRef Str) + : Loc(Loc), Namespace(Namespace.str()), Kind(Kind), Str(Str.str()) {} + + SourceLocation Loc; + std::string Namespace; + PPCallbacks::PragmaMessageKind Kind; + std::string Str; +}; + +struct PPMacroDefined : PPDirective { + PPMacroDefined(const Token &MacroNameTok, const MacroDirective *MD) : Name(MacroNameTok), MD(MD) {} + + Token Name; + const MacroDirective *MD; +}; + +struct PPMacroUndefined : PPDirective { + PPMacroUndefined(Token Name, const MacroDefinition *MD, + const MacroDirective *Undef) + : Name(Name), MD(MD), Undef(Undef) {} + + Token Name; + const MacroDefinition *MD; + const MacroDirective *Undef; +}; + +struct PPIf : PPDirective { + PPIf(SourceLocation Loc, SourceRange ConditionRange, + PPCallbacks::ConditionValueKind ConditionValue) + : Loc(Loc), ConditionRange(ConditionRange), + ConditionValue(ConditionValue) {} + + SourceLocation Loc; + SourceRange ConditionRange; + PPCallbacks::ConditionValueKind ConditionValue; + PPDirectiveList Directives; +}; + +struct PPElseIf : PPDirective { + PPElseIf(SourceLocation Loc, SourceRange ConditionRange, + PPCallbacks::ConditionValueKind ConditionValue, SourceLocation IfLoc) + : Loc(Loc), ConditionRange(ConditionRange), + ConditionValue(ConditionValue), IfLoc(IfLoc) {} + + SourceLocation Loc; + SourceRange ConditionRange; + PPCallbacks::ConditionValueKind ConditionValue; + SourceLocation IfLoc; + PPDirectiveList Directives; +}; + +struct PPIfDef : PPDirective { + PPIfDef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) + : Loc(Loc), Name(MacroNameTok), MD(&MD) {} + + SourceLocation Loc; + Token Name; + const MacroDefinition *MD; + PPDirectiveList Directives; +}; + +struct PPIfNotDef : PPDirective { + PPIfNotDef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) + : Loc(Loc), Name(MacroNameTok), MD(&MD) {} + + SourceLocation Loc; + Token Name; + const MacroDefinition *MD; + PPDirectiveList Directives; +}; + +struct PPElseIfDef : PPDirective { + PPElseIfDef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) + : Loc(Loc), Name(MacroNameTok), MD(&MD) {} + + SourceLocation Loc; + Token Name; + const MacroDefinition *MD; + PPDirectiveList Directives; +}; + +struct PPElseIfNotDef : PPDirective { + PPElseIfNotDef(SourceLocation Loc, const Token &MacroNameTok, + const MacroDefinition &MD) + : Loc(Loc), Name(MacroNameTok), MD(&MD) {} + + SourceLocation Loc; + Token Name; + const MacroDefinition *MD; + PPDirectiveList Directives; +}; + +struct PPEndIf : PPDirective { + PPEndIf(SourceLocation Loc, SourceLocation IfLoc) : Loc(Loc), IfLoc(IfLoc) {} + + SourceLocation Loc; + SourceLocation IfLoc; +}; + +struct PPElse : PPDirective { + PPElse(SourceLocation Loc, SourceLocation IfLoc) : Loc(Loc), IfLoc(IfLoc) {} + + SourceLocation Loc; + SourceLocation IfLoc; + PPDirectiveList Directives; +}; + +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 + +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 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( + 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(Loc, Str)}; + Directives->add(Directive.release()); +} + +void PPTreeBuilderCallbacks::PragmaDirective(SourceLocation Loc, + PragmaIntroducerKind Introducer) { + auto Directive{std::make_unique(Loc, Introducer)}; + Directives->add(Directive.release()); +} + +void PPTreeBuilderCallbacks::PragmaComment(SourceLocation Loc, + const IdentifierInfo *Kind, + StringRef Str) { + auto Directive{std::make_unique(Loc, Kind, Str)}; + Directives->add(Directive.release()); +} + +void PPTreeBuilderCallbacks::PragmaMark(SourceLocation Loc, StringRef Trivia) { + auto Directive{std::make_unique(Loc, Trivia)}; + Directives->add(Directive.release()); +} + +void PPTreeBuilderCallbacks::PragmaDetectMismatch(SourceLocation Loc, + StringRef Name, + StringRef Value) { + auto Directive{std::make_unique(Loc, Name, Value)}; + Directives->add(Directive.release()); +} + +void PPTreeBuilderCallbacks::PragmaDebug(SourceLocation Loc, + StringRef DebugType) { + auto Directive{std::make_unique(Loc, DebugType)}; + Directives->add(Directive.release()); +} + +void PPTreeBuilderCallbacks::PragmaMessage(SourceLocation Loc, + StringRef Namespace, + PragmaMessageKind Kind, + StringRef Str) { + auto Directive{std::make_unique(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(MacroNameTok, MD)}; + Directives->add(Directive.release()); +} + +void PPTreeBuilderCallbacks::MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD, + const MacroDirective *Undef) { + auto Directive{std::make_unique(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(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(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(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(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(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(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(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(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(Callback, SM, LangOpts)); +} + +} // namespace utils +} // namespace tidy +} // namespace clang