File indexing completed on 2024-04-28 13:34:27

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 &macroNameTok, const clang::SourceRange &, const clang::MacroInfo *minfo = nullptr);
0149     virtual void VisitMacroDefined(const clang::Token &macroNameTok);
0150     virtual void VisitDefined(const clang::Token &macroNameTok, 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