File indexing completed on 2024-04-14 05:32:06

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