File indexing completed on 2024-04-28 16:57:48

0001 /*
0002     This file is part of the clazy static checker.
0003 
0004     Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
0005     Author: SĂ©rgio Martins <sergio.martins@kdab.com>
0006 
0007     Copyright (C) 2015-2017 Sergio Martins <smartins@kde.org>
0008 
0009     This library is free software; you can redistribute it and/or
0010     modify it under the terms of the GNU Library General Public
0011     License as published by the Free Software Foundation; either
0012     version 2 of the License, or (at your option) any later version.
0013 
0014     This library is distributed in the hope that it will be useful,
0015     but WITHOUT ANY WARRANTY; without even the implied warranty of
0016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017     Library General Public License for more details.
0018 
0019     You should have received a copy of the GNU Library General Public License
0020     along with this library; see the file COPYING.LIB.  If not, write to
0021     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0022     Boston, MA 02110-1301, USA.
0023 */
0024 
0025 #ifndef CHECK_BASE_H
0026 #define CHECK_BASE_H
0027 
0028 #include "clazy_stl.h"
0029 #include "SourceCompatibilityHelpers.h"
0030 
0031 #include <clang/Basic/SourceManager.h>
0032 #include <clang/Frontend/CompilerInstance.h>
0033 #include <clang/Parse/Parser.h>
0034 #include <clang/ASTMatchers/ASTMatchers.h>
0035 #include <clang/ASTMatchers/ASTMatchFinder.h>
0036 #include <clang/AST/ASTContext.h>
0037 #include <clang/Basic/SourceLocation.h>
0038 #include <clang/Lex/PPCallbacks.h>
0039 #include <llvm/Config/llvm-config.h>
0040 
0041 #include <string>
0042 #include <utility>
0043 #include <vector>
0044 
0045 namespace clang {
0046 class CXXMethodDecl;
0047 class Stmt;
0048 class Decl;
0049 class TranslationUnitDecl;
0050 class FixItHint;
0051 class PresumedLoc;
0052 class SourceLocation;
0053 class PreprocessorOptions;
0054 class LangOptions;
0055 class MacroArgs;
0056 class MacroDefinition;
0057 class MacroDirective;
0058 class MacroInfo;
0059 class SourceManager;
0060 class Token;
0061 }
0062 
0063 class CheckBase;
0064 class ClazyContext;
0065 
0066 enum CheckLevel { // See README.md for what each level does
0067     CheckLevelUndefined = -1,
0068     CheckLevel0 = 0,
0069     CheckLevel1,
0070     CheckLevel2,
0071     ManualCheckLevel,
0072     MaxCheckLevel = CheckLevel2,
0073     DefaultCheckLevel = CheckLevel1
0074 };
0075 
0076 class ClazyPreprocessorCallbacks
0077     : public clang::PPCallbacks
0078 {
0079 public:
0080     ClazyPreprocessorCallbacks(const ClazyPreprocessorCallbacks &) = delete;
0081     explicit ClazyPreprocessorCallbacks(CheckBase *check);
0082 
0083     void MacroExpands(const clang::Token &MacroNameTok, const clang::MacroDefinition &,
0084                       clang::SourceRange, const clang::MacroArgs *) override;
0085     void MacroDefined(const clang::Token &MacroNameTok, const clang::MacroDirective*) override;
0086     void Defined(const clang::Token &MacroNameTok, const clang::MacroDefinition &, clang::SourceRange Range) override;
0087     void Ifdef(clang::SourceLocation, const clang::Token &MacroNameTok, const clang::MacroDefinition &) override;
0088     void Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok, const clang::MacroDefinition &) override;
0089     void If(clang::SourceLocation loc, clang::SourceRange conditionRange, clang::PPCallbacks::ConditionValueKind conditionValue) override;
0090     void Elif(clang::SourceLocation loc, clang::SourceRange conditionRange, clang::PPCallbacks::ConditionValueKind ConditionValue, clang::SourceLocation ifLoc) override;
0091     void Else(clang::SourceLocation loc, clang::SourceLocation ifLoc) override;
0092     void Endif(clang::SourceLocation loc, clang::SourceLocation ifLoc) override;
0093     void InclusionDirective(clang::SourceLocation HashLoc, const clang::Token &IncludeTok, clang::StringRef FileName, bool IsAngled,
0094                             clang::CharSourceRange FilenameRange, const clang::FileEntry *File, clang::StringRef SearchPath,
0095                             clang::StringRef RelativePath, const clang::Module *Imported, clang::SrcMgr::CharacteristicKind FileType) override;
0096 private:
0097     CheckBase *const check;
0098 };
0099 
0100 class ClazyAstMatcherCallback
0101     : public clang::ast_matchers::MatchFinder::MatchCallback
0102 {
0103 public:
0104     explicit ClazyAstMatcherCallback(CheckBase *check);
0105 protected:
0106     CheckBase *const m_check;
0107 };
0108 
0109 class CheckBase
0110 {
0111 public:
0112 
0113     enum Option {
0114         Option_None = 0,
0115         Option_CanIgnoreIncludes = 1
0116     };
0117     typedef int Options;
0118 
0119     typedef std::vector<CheckBase*> List;
0120     explicit CheckBase(const std::string &name, const ClazyContext *context,
0121                        Options = Option_None);
0122     CheckBase(const CheckBase &other) = delete;
0123 
0124     virtual ~CheckBase();
0125 
0126     std::string name() const { return m_name; }
0127 
0128     void emitWarning(const clang::Decl *, const std::string &error, bool printWarningTag = true);
0129     void emitWarning(const clang::Stmt *, const std::string &error, bool printWarningTag = true);
0130     void emitWarning(clang::SourceLocation loc, const std::string &error, bool printWarningTag = true);
0131     void emitWarning(clang::SourceLocation loc, std::string error, const std::vector<clang::FixItHint> &fixits, bool printWarningTag = true);
0132     void emitInternalError(clang::SourceLocation loc, std::string error);
0133 
0134     virtual void registerASTMatchers(clang::ast_matchers::MatchFinder &) {};
0135 
0136     bool canIgnoreIncludes() const
0137     {
0138         return m_options & Option_CanIgnoreIncludes;
0139     }
0140 
0141     virtual void VisitStmt(clang::Stmt *stm);
0142     virtual void VisitDecl(clang::Decl *decl);
0143 protected:
0144     virtual void VisitMacroExpands(const clang::Token &macroNameTok, const clang::SourceRange &, const clang::MacroInfo *minfo = nullptr);
0145     virtual void VisitMacroDefined(const clang::Token &macroNameTok);
0146     virtual void VisitDefined(const clang::Token &macroNameTok, const clang::SourceRange &);
0147     virtual void VisitIfdef(clang::SourceLocation, const clang::Token &);
0148     virtual void VisitIfndef(clang::SourceLocation, const clang::Token &);
0149     virtual void VisitIf(clang::SourceLocation loc, clang::SourceRange conditionRange, clang::PPCallbacks::ConditionValueKind conditionValue);
0150     virtual void VisitElif(clang::SourceLocation loc, clang::SourceRange conditionRange, clang::PPCallbacks::ConditionValueKind ConditionValue, clang::SourceLocation ifLoc);
0151     virtual void VisitElse(clang::SourceLocation loc, clang::SourceLocation ifLoc);
0152     virtual void VisitEndif(clang::SourceLocation loc, clang::SourceLocation ifLoc);
0153     virtual void VisitInclusionDirective(clang::SourceLocation HashLoc, const clang::Token &IncludeTok, clang::StringRef FileName, bool IsAngled,
0154                             clang::CharSourceRange FilenameRange, const clang::FileEntry *File, clang::StringRef SearchPath,
0155                             clang::StringRef RelativePath, const clang::Module *Imported, clang::SrcMgr::CharacteristicKind FileType);
0156 
0157     void enablePreProcessorCallbacks();
0158 
0159 
0160     bool shouldIgnoreFile(clang::SourceLocation) const;
0161     void reallyEmitWarning(clang::SourceLocation loc, const std::string &error, const std::vector<clang::FixItHint> &fixits);
0162 
0163     void queueManualFixitWarning(clang::SourceLocation loc, const std::string &message = {});
0164     bool warningAlreadyEmitted(clang::SourceLocation loc) const;
0165     bool manualFixitAlreadyQueued(clang::SourceLocation loc) const;
0166     bool isOptionSet(const std::string &optionName) const;
0167 
0168     // 3 shortcuts for stuff that litter the codebase all over.
0169     const clang::SourceManager &sm() const { return m_sm; }
0170     const clang::LangOptions &lo() const { return m_astContext.getLangOpts(); }
0171 
0172     const clang::SourceManager &m_sm;
0173     const std::string m_name;
0174     const ClazyContext *const m_context;
0175     clang::ASTContext &m_astContext;
0176     std::vector<std::string> m_filesToIgnore;
0177 private:
0178     friend class ClazyPreprocessorCallbacks;
0179     friend class ClazyAstMatcherCallback;
0180     ClazyPreprocessorCallbacks *const m_preprocessorCallbacks;
0181     std::vector<unsigned int> m_emittedWarningsInMacro;
0182     std::vector<unsigned int> m_emittedManualFixItsWarningsInMacro;
0183     std::vector<std::pair<clang::SourceLocation, std::string>> m_queuedManualInterventionWarnings;
0184     const Options m_options;
0185     const std::string m_tag;
0186 };
0187 
0188 #endif