diff options
Diffstat (limited to 'src/Clazy.cpp')
-rw-r--r-- | src/Clazy.cpp | 139 |
1 files changed, 66 insertions, 73 deletions
diff --git a/src/Clazy.cpp b/src/Clazy.cpp index c1ff2c67..0fcaed92 100644 --- a/src/Clazy.cpp +++ b/src/Clazy.cpp @@ -61,38 +61,56 @@ static void manuallyPopulateParentMap(ParentMap *map, Stmt *s) ClazyASTConsumer::ClazyASTConsumer(ClazyContext *context) : m_context(context) - , m_matchFinder(nullptr) { - clang::ast_matchers::MatchFinder::MatchFinderOptions options; #ifndef CLAZY_DISABLE_AST_MATCHERS - m_matchFinder = new clang::ast_matchers::MatchFinder(options); + m_matchFinder = new clang::ast_matchers::MatchFinder(); #endif } -void ClazyASTConsumer::addCheck(CheckBase *check) +void ClazyASTConsumer::addCheck(const std::pair<CheckBase *, RegisteredCheck> &check) { + CheckBase *checkBase = check.first; #ifndef CLAZY_DISABLE_AST_MATCHERS - check->registerASTMatchers(*m_matchFinder); + checkBase->registerASTMatchers(*m_matchFinder); #endif - m_createdChecks.push_back(check); + //m_createdChecks.push_back(checkBase); + + const RegisteredCheck &rcheck = check.second; + + if (rcheck.options & RegisteredCheck::Option_VisitsStmts) + m_checksToVisitStmts.push_back(checkBase); + + if (rcheck.options & RegisteredCheck::Option_VisitsDecls) + m_checksToVisitDecls.push_back(checkBase); + } ClazyASTConsumer::~ClazyASTConsumer() { - delete m_context; +#ifndef CLAZY_DISABLE_AST_MATCHERS delete m_matchFinder; +#endif + delete m_context; } bool ClazyASTConsumer::VisitDecl(Decl *decl) { - const bool isInSystemHeader = m_context->sm.isInSystemHeader(decl->getLocStart()); - - if (AccessSpecifierManager *a = m_context->accessSpecifierManager) + if (AccessSpecifierManager *a = m_context->accessSpecifierManager) // Needs to visit system headers too (qobject.h for example) a->VisitDeclaration(decl); - if (!isInSystemHeader) { - for (CheckBase *check : m_createdChecks) - check->VisitDeclaration(decl); + const SourceLocation locStart = getLocStart(decl); + if (locStart.isInvalid() || m_context->sm.isInSystemHeader(locStart)) + return true; + + const bool isFromIgnorableInclude = m_context->ignoresIncludedFiles() && !Utils::isMainFile(m_context->sm, locStart); + + m_context->lastDecl = decl; + if (auto mdecl = dyn_cast<CXXMethodDecl>(decl)) + m_context->lastMethodDecl = mdecl; + + for (CheckBase *check : m_checksToVisitDecls) { + if (!(isFromIgnorableInclude && check->canIgnoreIncludes())) + check->VisitDecl(decl); } return true; @@ -100,6 +118,10 @@ bool ClazyASTConsumer::VisitDecl(Decl *decl) bool ClazyASTConsumer::VisitStmt(Stmt *stm) { + const SourceLocation locStart = getLocStart(stm); + if (locStart.isInvalid() || m_context->sm.isInSystemHeader(locStart)) + return true; + if (!m_context->parentMap) { if (m_context->ci.getDiagnostics().hasUnrecoverableErrorOccurred()) return false; // ParentMap sometimes crashes when there were errors. Doesn't like a botched AST. @@ -122,10 +144,10 @@ bool ClazyASTConsumer::VisitStmt(Stmt *stm) if (!parentMap->hasParent(stm)) parentMap->addStmt(stm); - const bool isInSystemHeader = m_context->sm.isInSystemHeader(stm->getLocStart()); - if (!isInSystemHeader) { - for (CheckBase *check : m_createdChecks) - check->VisitStatement(stm); + const bool isFromIgnorableInclude = m_context->ignoresIncludedFiles() && !Utils::isMainFile(m_context->sm, locStart); + for (CheckBase *check : m_checksToVisitStmts) { + if (!(isFromIgnorableInclude && check->canIgnoreIncludes())) + check->VisitStmt(stm); } return true; @@ -147,7 +169,7 @@ void ClazyASTConsumer::HandleTranslationUnit(ASTContext &ctx) static bool parseArgument(const string &arg, vector<string> &args) { - auto it = clazy_std::find(args, arg); + auto it = clazy::find(args, arg); if (it != args.end()) { args.erase(it); return true; @@ -170,14 +192,22 @@ std::unique_ptr<clang::ASTConsumer> ClazyASTAction::CreateASTConsumer(CompilerIn std::lock_guard<std::mutex> lock(CheckManager::lock()); auto astConsumer = std::unique_ptr<ClazyASTConsumer>(new ClazyASTConsumer(m_context)); - CheckBase::List createdChecks = m_checkManager->createChecks(m_checks, m_context); - for (CheckBase *check : createdChecks) { + auto createdChecks = m_checkManager->createChecks(m_checks, m_context); + for (auto check : createdChecks) { astConsumer->addCheck(check); } return std::unique_ptr<clang::ASTConsumer>(astConsumer.release()); } +static std::string getEnvVariable(const char *name) +{ + const char *result = getenv(name); + if (result) + return result; + else return std::string(); +} + bool ClazyASTAction::ParseArgs(const CompilerInstance &ci, const std::vector<std::string> &args_) { // NOTE: This method needs to be kept reentrant (but not necessarily thread-safe) @@ -186,14 +216,8 @@ bool ClazyASTAction::ParseArgs(const CompilerInstance &ci, const std::vector<std std::vector<std::string> args = args_; if (parseArgument("help", args)) { - m_context = new ClazyContext(ci, ClazyContext::ClazyOption_None); - PrintHelp(llvm::errs(), HelpMode_Normal); - return true; - } - - if (parseArgument("generateAnchorHeader", args)) { - m_context = new ClazyContext(ci, ClazyContext::ClazyOption_None); - PrintHelp(llvm::errs(), HelpMode_AnchorHeader); + m_context = new ClazyContext(ci, getEnvVariable("CLAZY_HEADER_FILTER"), getEnvVariable("CLAZY_IGNORE_DIRS"), ClazyContext::ClazyOption_None); + PrintHelp(llvm::errs()); return true; } @@ -222,7 +246,10 @@ bool ClazyASTAction::ParseArgs(const CompilerInstance &ci, const std::vector<std if (parseArgument("visit-implicit-code", args)) m_options |= ClazyContext::ClazyOption_VisitImplicitCode; - m_context = new ClazyContext(ci, m_options); + if (parseArgument("ignore-included-files", args)) + m_options |= ClazyContext::ClazyOption_IgnoreIncludedFiles; + + m_context = new ClazyContext(ci, /*headerFilter=*/ "", /*ignoreDirs=*/ "", m_options); // This argument is for debugging purposes const bool dbgPrintRequestedChecks = parseArgument("print-requested-checks", args); @@ -269,48 +296,14 @@ void ClazyASTAction::printRequestedChecks() const llvm::errs() << "\n"; } -void ClazyASTAction::PrintAnchorHeader(llvm::raw_ostream &ros, RegisteredCheck::List &checks) const -{ - // Generates ClazyAnchorHeader.h. - // Needed so we can support a static build of clazy without the linker discarding our checks. - // You can generate with: - // $ echo | clang -Xclang -load -Xclang ClangLazy.so -Xclang -add-plugin -Xclang clang-lazy -Xclang -plugin-arg-clang-lazy -Xclang generateAnchorHeader -c -xc - - - - ros << "// This file was autogenerated.\n\n"; - ros << "#ifndef CLAZY_ANCHOR_HEADER_H\n#define CLAZY_ANCHOR_HEADER_H\n\n"; - - for (auto &check : checks) { - ros << string("extern volatile int ClazyAnchor_") + check.className + ";\n"; - } - - ros << "\n"; - ros << "int clazy_dummy()\n{\n"; - ros << " return\n"; - - for (auto &check : checks) { - ros << string(" ClazyAnchor_") + check.className + " +\n"; - } - - ros << " 0;\n"; - ros << "}\n\n"; - ros << "#endif\n"; -} - -void ClazyASTAction::PrintHelp(llvm::raw_ostream &ros, HelpMode helpMode) const +void ClazyASTAction::PrintHelp(llvm::raw_ostream &ros) const { std::lock_guard<std::mutex> lock(CheckManager::lock()); RegisteredCheck::List checks = m_checkManager->availableChecks(MaxCheckLevel); - clazy_std::sort(checks, checkLessThanByLevel); - - if (helpMode == HelpMode_AnchorHeader) { - PrintAnchorHeader(ros, checks); - return; - } + clazy::sort(checks, checkLessThanByLevel); ros << "Available checks and FixIts:\n\n"; - const bool useMarkdown = getenv("CLAZY_HELP_USE_MARKDOWN"); int lastPrintedLevel = -1; const auto numChecks = checks.size(); @@ -330,7 +323,7 @@ void ClazyASTAction::PrintHelp(llvm::raw_ostream &ros, HelpMode helpMode) const auto padded = check.name; padded.insert(padded.end(), 39 - padded.size(), ' '); - ros << " - " << (useMarkdown ? "[" : "") << check.name << (useMarkdown ? "](" + relativeReadmePath + ")" : ""); + ros << " - " << check.name;; auto fixits = m_checkManager->availableFixIts(check.name); if (!fixits.empty()) { ros << " ("; @@ -361,19 +354,19 @@ void ClazyASTAction::PrintHelp(llvm::raw_ostream &ros, HelpMode helpMode) const ros << "FixIts are experimental and rewrite your code therefore only one FixIt is allowed per build.\nSpecifying a list of different FixIts is not supported.\nBackup your code before running them.\n"; } -ClazyStandaloneASTAction::ClazyStandaloneASTAction(const string &checkList, +ClazyStandaloneASTAction::ClazyStandaloneASTAction(const string &checkList, const string &headerFilter, const string &ignoreDirs, ClazyContext::ClazyOptions options) : clang::ASTFrontendAction() - , m_checkList(checkList) + , m_checkList(checkList.empty() ? "level1" : checkList) + , m_headerFilter(headerFilter.empty() ? getEnvVariable("CLAZY_HEADER_FILTER") : headerFilter) + , m_ignoreDirs(ignoreDirs.empty() ? getEnvVariable("CLAZY_IGNORE_DIRS") : ignoreDirs) , m_options(options) { - if (m_checkList.empty()) - m_checkList = "level1"; } unique_ptr<ASTConsumer> ClazyStandaloneASTAction::CreateASTConsumer(CompilerInstance &ci, llvm::StringRef) { - auto context = new ClazyContext(ci, m_options); + auto context = new ClazyContext(ci, m_headerFilter, m_ignoreDirs, m_options); auto astConsumer = new ClazyASTConsumer(context); auto cm = CheckManager::instance(); @@ -386,8 +379,8 @@ unique_ptr<ASTConsumer> ClazyStandaloneASTAction::CreateASTConsumer(CompilerInst return nullptr; } - CheckBase::List createdChecks = cm->createChecks(requestedChecks, context); - for (CheckBase *check : createdChecks) { + auto createdChecks = cm->createChecks(requestedChecks, context); + for (const auto &check : createdChecks) { astConsumer->addCheck(check); } |