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

0001 /*
0002     This file is part of the clazy static checker.
0003 
0004     Copyright (C) 2017 Sergio Martins <smartins@kde.org>
0005 
0006     This library is free software; you can redistribute it and/or
0007     modify it under the terms of the GNU Library General Public
0008     License as published by the Free Software Foundation; either
0009     version 2 of the License, or (at your option) any later version.
0010 
0011     This library is distributed in the hope that it will be useful,
0012     but WITHOUT ANY WARRANTY; without even the implied warranty of
0013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014     Library General Public License for more details.
0015 
0016     You should have received a copy of the GNU Library General Public License
0017     along with this library; see the file COPYING.LIB.  If not, write to
0018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019     Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #ifndef CLAZY_CONTEXT_H
0023 #define CLAZY_CONTEXT_H
0024 
0025 #include "SuppressionManager.h"
0026 #include "clazy_stl.h"
0027 
0028 #include <clang/Frontend/CompilerInstance.h>
0029 #include <clang/Lex/PreprocessorOptions.h>
0030 #include <clang/Basic/FileManager.h>
0031 #include <clang/Basic/SourceLocation.h>
0032 #include <clang/Basic/SourceManager.h>
0033 #include <llvm/Support/Regex.h>
0034 #include <llvm/ADT/StringRef.h>
0035 
0036 #include <string>
0037 #include <vector>
0038 #include <memory>
0039 #include <utility>
0040 
0041 // ClazyContext is just a struct to share data and code between all checks
0042 
0043 namespace clang {
0044 class CompilerInstance;
0045 class ASTContext;
0046 class ParentMap;
0047 class SourceManager;
0048 class CXXMethodDecl;
0049 class Decl;
0050 }
0051 
0052 class AccessSpecifierManager;
0053 class PreProcessorVisitor;
0054 class FixItExporter;
0055 
0056 class ClazyContext
0057 {
0058 public:
0059     enum ClazyOption {
0060         ClazyOption_None = 0,
0061         ClazyOption_ExportFixes = 1,
0062         ClazyOption_Qt4Compat = 2,
0063         ClazyOption_OnlyQt = 4, // Ignore non-Qt files. This is done by bailing out if QT_CORE_LIB is not set.
0064         ClazyOption_QtDeveloper = 8, // For running clazy on Qt itself, optional, but honours specific guidelines
0065         ClazyOption_VisitImplicitCode = 16, // Inspect compiler generated code aswell, useful for custom checks, if they need it
0066         ClazyOption_IgnoreIncludedFiles = 32 // Only warn for the current file being compiled, not on includes (useful for performance reasons)
0067     };
0068     typedef int ClazyOptions;
0069 
0070     explicit ClazyContext(const clang::CompilerInstance &ci,
0071                           const std::string &headerFilter,
0072                           const std::string &ignoreDirs,
0073                           std::string exportFixesFilename,
0074                           const std::vector<std::string> &translationUnitPaths,
0075                           ClazyOptions = ClazyOption_None);
0076     ~ClazyContext();
0077 
0078     bool usingPreCompiledHeaders() const
0079     {
0080         return !ci.getPreprocessorOpts().ImplicitPCHInclude.empty();
0081     }
0082 
0083     bool userDisabledWError() const
0084     {
0085         return m_noWerror;
0086     }
0087 
0088     bool exportFixesEnabled() const
0089     {
0090         return options & ClazyOption_ExportFixes;
0091     }
0092 
0093     bool isQtDeveloper() const
0094     {
0095         return options & ClazyOption_QtDeveloper;
0096     }
0097 
0098     bool ignoresIncludedFiles() const
0099     {
0100         return options & ClazyOption_IgnoreIncludedFiles;
0101     }
0102 
0103     bool isVisitImplicitCode() const
0104     {
0105         return options & ClazyContext::ClazyOption_VisitImplicitCode;
0106     }
0107 
0108     bool isOptionSet(const std::string &optionName) const
0109     {
0110         return clazy::contains(extraOptions, optionName);
0111     }
0112 
0113     bool fileMatchesLoc(const std::unique_ptr<llvm::Regex> &regex, clang::SourceLocation loc,  const clang::FileEntry **file) const
0114     {
0115         if (!regex)
0116             return false;
0117 
0118         if (!(*file)) {
0119             clang::FileID fid = sm.getDecomposedExpansionLoc(loc).first;
0120             *file = sm.getFileEntryForID(fid);
0121             if (!(*file)) {
0122                 return false;
0123             }
0124         }
0125 
0126         llvm::StringRef fileName((*file)->getName());
0127         return regex->match(fileName);
0128     }
0129 
0130     bool shouldIgnoreFile(clang::SourceLocation loc) const
0131     {
0132         // 1. Process the regexp that excludes files
0133         const clang::FileEntry *file = nullptr;
0134         if (ignoreDirsRegex) {
0135             const bool matches = fileMatchesLoc(ignoreDirsRegex, loc, &file);
0136             if (matches)
0137                 return true;
0138         }
0139 
0140         // 2. Process the regexp that includes files. Has lower priority.
0141         if (!headerFilterRegex || isMainFile(loc))
0142             return false;
0143 
0144         const bool matches = fileMatchesLoc(headerFilterRegex, loc, &file);
0145         if (!file)
0146             return false;
0147 
0148         return !matches;
0149     }
0150 
0151     bool isMainFile(clang::SourceLocation loc) const
0152     {
0153         if (loc.isMacroID())
0154             loc = sm.getExpansionLoc(loc);
0155 
0156         return sm.isInFileID(loc, sm.getMainFileID());
0157     }
0158 
0159     bool treatAsError(const std::string &checkName) const
0160     {
0161         return clazy::contains(m_checksPromotedToErrors, checkName);
0162     }
0163 
0164     /**
0165      * We only enable it if a check needs it, for performance reasons
0166      */
0167     void enableAccessSpecifierManager();
0168     void enablePreprocessorVisitor();
0169     void enableVisitallTypeDefs();
0170     bool visitsAllTypedefs() const;
0171 
0172     bool isQt() const;
0173 
0174     // TODO: More things will follow
0175     const clang::CompilerInstance &ci;
0176     clang::ASTContext &astContext;
0177     clang::SourceManager &sm;
0178     AccessSpecifierManager *accessSpecifierManager = nullptr;
0179     PreProcessorVisitor *preprocessorVisitor = nullptr;
0180     SuppressionManager suppressionManager;
0181     const bool m_noWerror;
0182     std::vector<std::string> m_checksPromotedToErrors;
0183     bool m_visitsAllTypeDefs = false;
0184     clang::ParentMap *parentMap = nullptr;
0185     const ClazyOptions options;
0186     const std::vector<std::string> extraOptions;
0187     FixItExporter *exporter = nullptr;
0188     clang::CXXMethodDecl *lastMethodDecl = nullptr;
0189     clang::FunctionDecl *lastFunctionDecl = nullptr;
0190     clang::Decl *lastDecl = nullptr;
0191     std::unique_ptr<llvm::Regex> headerFilterRegex;
0192     std::unique_ptr<llvm::Regex> ignoreDirsRegex;
0193     const std::vector<std::string> m_translationUnitPaths;
0194 };
0195 
0196 #endif