File indexing completed on 2024-04-21 05:38:46

0001 /*
0002     SPDX-FileCopyrightText: 2017 Sergio Martins <smartins@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "ClazyContext.h"
0008 #include "AccessSpecifierManager.h"
0009 #include "FixItExporter.h"
0010 #include "PreProcessorVisitor.h"
0011 #include "checkmanager.h"
0012 
0013 #include <clang/AST/ParentMap.h>
0014 #include <clang/Frontend/CompilerInstance.h>
0015 #include <clang/Lex/PreprocessorOptions.h>
0016 #include <clang/Rewrite/Frontend/FixItRewriter.h>
0017 #include <llvm/Support/Regex.h>
0018 
0019 #include <stdlib.h>
0020 
0021 using namespace clang;
0022 
0023 ClazyContext::ClazyContext(const clang::CompilerInstance &compiler,
0024                            const std::string &headerFilter,
0025                            const std::string &ignoreDirs,
0026                            std::string exportFixesFilename,
0027                            const std::vector<std::string> &translationUnitPaths,
0028                            ClazyOptions opts)
0029     : ci(compiler)
0030     , astContext(ci.getASTContext())
0031     , sm(ci.getSourceManager())
0032     , m_noWerror(getenv("CLAZY_NO_WERROR") != nullptr) // Allows user to make clazy ignore -Werror
0033     , m_checksPromotedToErrors(CheckManager::instance()->checksAsErrors())
0034     , options(opts)
0035     , extraOptions(clazy::splitString(getenv("CLAZY_EXTRA_OPTIONS"), ','))
0036     , m_translationUnitPaths(translationUnitPaths)
0037 {
0038     if (!headerFilter.empty()) {
0039         headerFilterRegex = std::unique_ptr<llvm::Regex>(new llvm::Regex(headerFilter));
0040     }
0041 
0042     if (!ignoreDirs.empty()) {
0043         ignoreDirsRegex = std::unique_ptr<llvm::Regex>(new llvm::Regex(ignoreDirs));
0044     }
0045 
0046     if (exportFixesEnabled()) {
0047         if (exportFixesFilename.empty()) {
0048             // Only clazy-standalone sets the filename by argument.
0049             // clazy plugin sets it automatically here:
0050             const FileEntry *fileEntry = sm.getFileEntryForID(sm.getMainFileID());
0051             exportFixesFilename = fileEntry->getName().str() + ".clazy.yaml";
0052         }
0053 
0054         const bool isClazyStandalone = !translationUnitPaths.empty();
0055         exporter = new FixItExporter(ci.getDiagnostics(), sm, ci.getLangOpts(), exportFixesFilename, isClazyStandalone);
0056     }
0057 }
0058 
0059 ClazyContext::~ClazyContext()
0060 {
0061     // delete preprocessorVisitor; // we don't own it
0062     delete accessSpecifierManager;
0063     delete parentMap;
0064 
0065     static unsigned long count = 0;
0066     count++;
0067 
0068     if (exporter) {
0069         // With clazy-standalone we use the same YAML file for all translation-units, so only
0070         // write out the last one. With clazy-plugin there's a YAML file per translation unit.
0071         const bool isClazyPlugin = m_translationUnitPaths.empty();
0072         const bool isLast = count == m_translationUnitPaths.size();
0073         if (isLast || isClazyPlugin) {
0074             exporter->Export();
0075         }
0076         delete exporter;
0077     }
0078 
0079     preprocessorVisitor = nullptr;
0080     accessSpecifierManager = nullptr;
0081     parentMap = nullptr;
0082 }
0083 
0084 void ClazyContext::enableAccessSpecifierManager()
0085 {
0086     if (!accessSpecifierManager && !usingPreCompiledHeaders()) {
0087         accessSpecifierManager = new AccessSpecifierManager(this);
0088     }
0089 }
0090 
0091 void ClazyContext::enablePreprocessorVisitor()
0092 {
0093     if (!preprocessorVisitor && !usingPreCompiledHeaders()) {
0094         preprocessorVisitor = new PreProcessorVisitor(ci);
0095     }
0096 }
0097 
0098 void ClazyContext::enableVisitallTypeDefs()
0099 {
0100     // By default we only process decls from the .cpp file we're processing, not stuff included (for performance)
0101     /// But we might need to process all typedefs, not only the ones in our current .cpp files
0102     m_visitsAllTypeDefs = true;
0103 }
0104 
0105 bool ClazyContext::visitsAllTypedefs() const
0106 {
0107     return m_visitsAllTypeDefs;
0108 }
0109 
0110 bool ClazyContext::isQt() const
0111 {
0112     static const bool s_isQt = [this] {
0113         for (const auto &s : ci.getPreprocessorOpts().Macros) {
0114             if (s.first == "QT_CORE_LIB") {
0115                 return true;
0116             }
0117         }
0118         return false;
0119     }();
0120 
0121     return s_isQt;
0122 }