File indexing completed on 2024-03-24 05:41:38
0001 /* 0002 SPDX-FileCopyrightText: 2015 Klarälvdalens Datakonsult AB a KDAB Group company info@kdab.com 0003 SPDX-FileContributor: SĂ©rgio Martins <sergio.martins@kdab.com> 0004 0005 SPDX-FileCopyrightText: 2015-2017 Sergio Martins <smartins@kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #ifndef CHECK_BASE_H 0011 #define CHECK_BASE_H 0012 0013 #include "clazy_stl.h" // IWYU pragma: keep 0014 0015 #include <clang/AST/ASTContext.h> 0016 #include <clang/ASTMatchers/ASTMatchFinder.h> 0017 #include <clang/ASTMatchers/ASTMatchers.h> 0018 #include <clang/Basic/SourceLocation.h> 0019 #include <clang/Basic/SourceManager.h> 0020 #include <clang/Frontend/CompilerInstance.h> 0021 #include <clang/Lex/PPCallbacks.h> 0022 #include <clang/Parse/Parser.h> 0023 #include <llvm/Config/llvm-config.h> 0024 0025 #include <string> 0026 #include <utility> 0027 #include <vector> 0028 0029 namespace clazy 0030 { 0031 #if LLVM_VERSION_MAJOR >= 16 0032 using OptionalFileEntryRef = clang::CustomizableOptional<clang::FileEntryRef>; 0033 #elif LLVM_VERSION_MAJOR >= 15 0034 using OptionalFileEntryRef = clang::Optional<clang::FileEntryRef>; 0035 #else 0036 using OptionalFileEntryRef = const clang::FileEntry *; 0037 #endif 0038 } 0039 0040 namespace clang 0041 { 0042 class CXXMethodDecl; 0043 class Stmt; 0044 class Decl; 0045 class TranslationUnitDecl; 0046 class FixItHint; 0047 class PresumedLoc; 0048 class SourceLocation; 0049 class PreprocessorOptions; 0050 class LangOptions; 0051 class MacroArgs; 0052 class MacroDefinition; 0053 class MacroDirective; 0054 class MacroInfo; 0055 class SourceManager; 0056 class Token; 0057 } 0058 0059 class CheckBase; 0060 class ClazyContext; 0061 0062 enum CheckLevel { // See README.md for what each level does 0063 CheckLevelUndefined = -1, 0064 CheckLevel0 = 0, 0065 CheckLevel1, 0066 CheckLevel2, 0067 ManualCheckLevel, 0068 MaxCheckLevel = CheckLevel2, 0069 DefaultCheckLevel = CheckLevel1 0070 }; 0071 0072 class ClazyPreprocessorCallbacks : public clang::PPCallbacks 0073 { 0074 public: 0075 ClazyPreprocessorCallbacks(const ClazyPreprocessorCallbacks &) = delete; 0076 explicit ClazyPreprocessorCallbacks(CheckBase *check); 0077 0078 void MacroExpands(const clang::Token &MacroNameTok, const clang::MacroDefinition &, clang::SourceRange, const clang::MacroArgs *) override; 0079 void MacroDefined(const clang::Token &MacroNameTok, const clang::MacroDirective *) override; 0080 void Defined(const clang::Token &MacroNameTok, const clang::MacroDefinition &, clang::SourceRange Range) override; 0081 void Ifdef(clang::SourceLocation, const clang::Token &MacroNameTok, const clang::MacroDefinition &) override; 0082 void Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok, const clang::MacroDefinition &) override; 0083 void If(clang::SourceLocation loc, clang::SourceRange conditionRange, clang::PPCallbacks::ConditionValueKind conditionValue) override; 0084 void Elif(clang::SourceLocation loc, 0085 clang::SourceRange conditionRange, 0086 clang::PPCallbacks::ConditionValueKind ConditionValue, 0087 clang::SourceLocation ifLoc) override; 0088 void Else(clang::SourceLocation loc, clang::SourceLocation ifLoc) override; 0089 void Endif(clang::SourceLocation loc, clang::SourceLocation ifLoc) override; 0090 void InclusionDirective(clang::SourceLocation HashLoc, 0091 const clang::Token &IncludeTok, 0092 clang::StringRef FileName, 0093 bool IsAngled, 0094 clang::CharSourceRange FilenameRange, 0095 clazy::OptionalFileEntryRef File, 0096 clang::StringRef SearchPath, 0097 clang::StringRef RelativePath, 0098 const clang::Module *Imported, 0099 clang::SrcMgr::CharacteristicKind FileType) override; 0100 0101 private: 0102 CheckBase *const check; 0103 }; 0104 0105 class ClazyAstMatcherCallback : public clang::ast_matchers::MatchFinder::MatchCallback 0106 { 0107 public: 0108 explicit ClazyAstMatcherCallback(CheckBase *check); 0109 0110 protected: 0111 CheckBase *const m_check; 0112 }; 0113 0114 class CheckBase 0115 { 0116 public: 0117 enum Option { Option_None = 0, Option_CanIgnoreIncludes = 1 }; 0118 using Options = int; 0119 0120 using List = std::vector<CheckBase *>; 0121 explicit CheckBase(const std::string &name, const ClazyContext *context, Options = Option_None); 0122 CheckBase(const CheckBase &other) = delete; 0123 0124 virtual ~CheckBase(); 0125 0126 std::string name() const 0127 { 0128 return m_name; 0129 } 0130 0131 void emitWarning(const clang::Decl *, const std::string &error, bool printWarningTag = true); 0132 void emitWarning(const clang::Stmt *, const std::string &error, bool printWarningTag = true); 0133 void emitWarning(clang::SourceLocation loc, const std::string &error, bool printWarningTag = true); 0134 void emitWarning(clang::SourceLocation loc, std::string error, const std::vector<clang::FixItHint> &fixits, bool printWarningTag = true); 0135 void emitInternalError(clang::SourceLocation loc, std::string error); 0136 0137 virtual void registerASTMatchers(clang::ast_matchers::MatchFinder &){}; 0138 0139 bool canIgnoreIncludes() const 0140 { 0141 return m_options & Option_CanIgnoreIncludes; 0142 } 0143 0144 virtual void VisitStmt(clang::Stmt *stm); 0145 virtual void VisitDecl(clang::Decl *decl); 0146 0147 protected: 0148 virtual void VisitMacroExpands(const clang::Token ¯oNameTok, const clang::SourceRange &, const clang::MacroInfo *minfo = nullptr); 0149 virtual void VisitMacroDefined(const clang::Token ¯oNameTok); 0150 virtual void VisitDefined(const clang::Token ¯oNameTok, const clang::SourceRange &); 0151 virtual void VisitIfdef(clang::SourceLocation, const clang::Token &); 0152 virtual void VisitIfndef(clang::SourceLocation, const clang::Token &); 0153 virtual void VisitIf(clang::SourceLocation loc, clang::SourceRange conditionRange, clang::PPCallbacks::ConditionValueKind conditionValue); 0154 virtual void 0155 VisitElif(clang::SourceLocation loc, clang::SourceRange conditionRange, clang::PPCallbacks::ConditionValueKind ConditionValue, clang::SourceLocation ifLoc); 0156 virtual void VisitElse(clang::SourceLocation loc, clang::SourceLocation ifLoc); 0157 virtual void VisitEndif(clang::SourceLocation loc, clang::SourceLocation ifLoc); 0158 virtual void VisitInclusionDirective(clang::SourceLocation HashLoc, 0159 const clang::Token &IncludeTok, 0160 clang::StringRef FileName, 0161 bool IsAngled, 0162 clang::CharSourceRange FilenameRange, 0163 clazy::OptionalFileEntryRef File, 0164 clang::StringRef SearchPath, 0165 clang::StringRef RelativePath, 0166 const clang::Module *Imported, 0167 clang::SrcMgr::CharacteristicKind FileType); 0168 0169 void enablePreProcessorCallbacks(); 0170 0171 bool shouldIgnoreFile(clang::SourceLocation) const; 0172 void reallyEmitWarning(clang::SourceLocation loc, const std::string &error, const std::vector<clang::FixItHint> &fixits); 0173 0174 void queueManualFixitWarning(clang::SourceLocation loc, const std::string &message = {}); 0175 bool warningAlreadyEmitted(clang::SourceLocation loc) const; 0176 bool manualFixitAlreadyQueued(clang::SourceLocation loc) const; 0177 bool isOptionSet(const std::string &optionName) const; 0178 0179 // 3 shortcuts for stuff that litter the codebase all over. 0180 const clang::SourceManager &sm() const 0181 { 0182 return m_sm; 0183 } 0184 const clang::LangOptions &lo() const 0185 { 0186 return m_astContext.getLangOpts(); 0187 } 0188 0189 const clang::SourceManager &m_sm; 0190 const std::string m_name; 0191 const ClazyContext *const m_context; 0192 clang::ASTContext &m_astContext; 0193 std::vector<std::string> m_filesToIgnore; 0194 0195 private: 0196 friend class ClazyPreprocessorCallbacks; 0197 friend class ClazyAstMatcherCallback; 0198 ClazyPreprocessorCallbacks *const m_preprocessorCallbacks; 0199 std::vector<unsigned int> m_emittedWarningsInMacro; 0200 std::vector<unsigned int> m_emittedManualFixItsWarningsInMacro; 0201 std::vector<std::pair<clang::SourceLocation, std::string>> m_queuedManualInterventionWarnings; 0202 const Options m_options; 0203 const std::string m_tag; 0204 }; 0205 0206 #endif