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

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