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 + 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 ? "\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(Directive)) + dumpMacroDefined(SM, Def); + else if (const PPInclusion *I = dyn_cast(Directive)) + dumpInclusion(SM, I); + else if (const PPIdent *ID = dyn_cast(Directive)) + dumpIdent(SM, ID); + else if (const PPPragma *P = dyn_cast(Directive)) + dumpPragma(SM, P); + else if (const PPPragmaComment *C = dyn_cast(Directive)) + dumpPragmaComment(SM, C); + else if (const PPPragmaMark *M = dyn_cast(Directive)) + dumpPragmaMark(SM, M); + else if (const PPPragmaDetectMismatch *MM = + dyn_cast(Directive)) + dumpPragmaDetectMismatch(SM, MM); + else if (const PPPragmaDebug *Dbg = dyn_cast(Directive)) + dumpPragmaDebug(SM, Dbg); + else if (const PPPragmaMessage *Msg = dyn_cast(Directive)) + dumpPragmaMessage(SM, Msg); + else if (const PPMacroUndefined *Undef = + dyn_cast(Directive)) + dumpMacroUndefined(SM, Undef); + else if (const PPIf *If = dyn_cast(Directive)) + dumpIf(SM, If); + else if (const PPElse *Else = dyn_cast(Directive)) + dumpElse(SM, Else); + else if (const PPElseIf *ElseIf = dyn_cast(Directive)) + dumpElseIf(SM, ElseIf); + else if (const PPIfDef *IfDef = dyn_cast(Directive)) + dumpIfDef(SM, IfDef); + else if (const PPIfNotDef *IfNotDef = dyn_cast(Directive)) + dumpIfNotDef(SM, IfNotDef); + else if (const PPElseIfDef *ElseIfDef = dyn_cast(Directive)) + dumpElseIfDef(SM, ElseIfDef); + else if (const PPElseIfNotDef *ElseIfNotDef = + dyn_cast(Directive)) + dumpElseIfNotDef(SM, ElseIfNotDef); + else if (const PPEndIf *EndIf = dyn_cast(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 TreeConsumer; +static std::unique_ptr 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()) 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,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 + +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; + +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 + +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