diff options
Diffstat (limited to 'lib/StaticAnalyzer/Frontend')
-rw-r--r-- | lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp | 138 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp | 25 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Frontend/ModelInjector.cpp | 1 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Frontend/ModelInjector.h | 4 |
4 files changed, 117 insertions, 51 deletions
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 8ac229fc6583..b3e287ebf815 100644 --- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -13,17 +13,14 @@ #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" #include "ModelInjector.h" -#include "clang/AST/ASTConsumer.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" -#include "clang/AST/ParentMap.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CallGraph.h" #include "clang/Analysis/CodeInjector.h" -#include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/Preprocessor.h" @@ -36,9 +33,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" -#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/PostOrderIterator.h" -#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -118,16 +113,28 @@ public: Diag.Report(WarnLoc, WarnID) << PD->getShortDescription() << PD->path.back()->getRanges(); + // First, add extra notes, even if paths should not be included. + for (const auto &Piece : PD->path) { + if (!isa<PathDiagnosticNotePiece>(Piece.get())) + continue; + + SourceLocation NoteLoc = Piece->getLocation().asLocation(); + Diag.Report(NoteLoc, NoteID) << Piece->getString() + << Piece->getRanges(); + } + if (!IncludePath) continue; + // Then, add the path notes if necessary. PathPieces FlatPath = PD->path.flatten(/*ShouldFlattenMacros=*/true); - for (PathPieces::const_iterator PI = FlatPath.begin(), - PE = FlatPath.end(); - PI != PE; ++PI) { - SourceLocation NoteLoc = (*PI)->getLocation().asLocation(); - Diag.Report(NoteLoc, NoteID) << (*PI)->getString() - << (*PI)->getRanges(); + for (const auto &Piece : FlatPath) { + if (isa<PathDiagnosticNotePiece>(Piece.get())) + continue; + + SourceLocation NoteLoc = Piece->getLocation().asLocation(); + Diag.Report(NoteLoc, NoteID) << Piece->getString() + << Piece->getRanges(); } } } @@ -193,14 +200,16 @@ public: Injector(injector) { DigestAnalyzerOptions(); if (Opts->PrintStats) { - llvm::EnableStatistics(); - TUTotalTimer = new llvm::Timer("Analyzer Total Time"); + llvm::EnableStatistics(false); + TUTotalTimer = new llvm::Timer("time", "Analyzer Total Time"); } } ~AnalysisConsumer() override { - if (Opts->PrintStats) + if (Opts->PrintStats) { delete TUTotalTimer; + llvm::PrintStatistics(); + } } void DigestAnalyzerOptions() { @@ -270,19 +279,8 @@ public: else assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!"); - llvm::errs() << ": " << Loc.getFilename(); - if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { - const NamedDecl *ND = cast<NamedDecl>(D); - llvm::errs() << ' ' << ND->getQualifiedNameAsString() << '\n'; - } - else if (isa<BlockDecl>(D)) { - llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:" - << Loc.getColumn() << '\n'; - } - else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - Selector S = MD->getSelector(); - llvm::errs() << ' ' << S.getAsString(); - } + llvm::errs() << ": " << Loc.getFilename() << ' ' + << getFunctionName(D) << '\n'; } } @@ -382,6 +380,7 @@ public: private: void storeTopLevelDecls(DeclGroupRef DG); + std::string getFunctionName(const Decl *D); /// \brief Check if we should skip (not analyze) the given function. AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode); @@ -431,6 +430,13 @@ static bool shouldSkipFunction(const Decl *D, // Count naming convention errors more aggressively. if (isa<ObjCMethodDecl>(D)) return false; + // We also want to reanalyze all C++ copy and move assignment operators to + // separately check the two cases where 'this' aliases with the parameter and + // where it may not. (cplusplus.SelfAssignmentChecker) + if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { + if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) + return false; + } // Otherwise, if we visited the function before, do not reanalyze it. return Visited.count(D); @@ -442,9 +448,7 @@ AnalysisConsumer::getInliningModeForFunction(const Decl *D, // We want to reanalyze all ObjC methods as top level to report Retain // Count naming convention errors more aggressively. But we should tune down // inlining when reanalyzing an already inlined function. - if (Visited.count(D)) { - assert(isa<ObjCMethodDecl>(D) && - "We are only reanalyzing ObjCMethods."); + if (Visited.count(D) && isa<ObjCMethodDecl>(D)) { const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D); if (ObjCM->getMethodFamily() != OMF_init) return ExprEngine::Inline_Minimal; @@ -568,16 +572,64 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { } -static std::string getFunctionName(const Decl *D) { - if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) { - return ID->getSelector().getAsString(); - } - if (const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) { - IdentifierInfo *II = ND->getIdentifier(); - if (II) - return II->getName(); +std::string AnalysisConsumer::getFunctionName(const Decl *D) { + std::string Str; + llvm::raw_string_ostream OS(Str); + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + OS << FD->getQualifiedNameAsString(); + + // In C++, there are overloads. + if (Ctx->getLangOpts().CPlusPlus) { + OS << '('; + for (const auto &P : FD->parameters()) { + if (P != *FD->param_begin()) + OS << ", "; + OS << P->getType().getAsString(); + } + OS << ')'; + } + + } else if (isa<BlockDecl>(D)) { + PresumedLoc Loc = Ctx->getSourceManager().getPresumedLoc(D->getLocation()); + + if (Loc.isValid()) { + OS << "block (line: " << Loc.getLine() << ", col: " << Loc.getColumn() + << ')'; + } + + } else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) { + + // FIXME: copy-pasted from CGDebugInfo.cpp. + OS << (OMD->isInstanceMethod() ? '-' : '+') << '['; + const DeclContext *DC = OMD->getDeclContext(); + if (const auto *OID = dyn_cast<ObjCImplementationDecl>(DC)) { + OS << OID->getName(); + } else if (const auto *OID = dyn_cast<ObjCInterfaceDecl>(DC)) { + OS << OID->getName(); + } else if (const auto *OC = dyn_cast<ObjCCategoryDecl>(DC)) { + if (OC->IsClassExtension()) { + OS << OC->getClassInterface()->getName(); + } else { + OS << OC->getIdentifier()->getNameStart() << '(' + << OC->getIdentifier()->getNameStart() << ')'; + } + } else if (const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) { + OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' + << OCD->getIdentifier()->getNameStart() << ')'; + } else if (isa<ObjCProtocolDecl>(DC)) { + // We can extract the type of the class from the self pointer. + if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) { + QualType ClassTy = + cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType(); + ClassTy.print(OS, PrintingPolicy(LangOptions())); + } + } + OS << ' ' << OMD->getSelector().getAsString() << ']'; + } - return ""; + + return OS.str(); } AnalysisConsumer::AnalysisMode @@ -614,6 +666,12 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, if (Mode == AM_None) return; + // Clear the AnalysisManager of old AnalysisDeclContexts. + Mgr->ClearContexts(); + // Ignore autosynthesized code. + if (Mgr->getAnalysisDeclContext(D)->isBodyAutosynthesized()) + return; + DisplayFunction(D, Mode, IMode); CFG *DeclCFG = Mgr->getCFG(D); if (DeclCFG) { @@ -621,8 +679,6 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize; } - // Clear the AnalysisManager of old AnalysisDeclContexts. - Mgr->ClearContexts(); BugReporter BR(*Mgr); if (Mode & AM_Syntax) diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp index 75fa4c651ace..31b6638e651f 100644 --- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -101,6 +101,16 @@ void ClangCheckerRegistry::warnIncompatible(DiagnosticsEngine *diags, << pluginAPIVersion; } +static SmallVector<CheckerOptInfo, 8> +getCheckerOptList(const AnalyzerOptions &opts) { + SmallVector<CheckerOptInfo, 8> checkerOpts; + for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) { + const std::pair<std::string, bool> &opt = opts.CheckersControlList[i]; + checkerOpts.push_back(CheckerOptInfo(opt.first, opt.second)); + } + return checkerOpts; +} + std::unique_ptr<CheckerManager> ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, ArrayRef<std::string> plugins, @@ -108,11 +118,7 @@ ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts, std::unique_ptr<CheckerManager> checkerMgr( new CheckerManager(langOpts, &opts)); - SmallVector<CheckerOptInfo, 8> checkerOpts; - for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) { - const std::pair<std::string, bool> &opt = opts.CheckersControlList[i]; - checkerOpts.push_back(CheckerOptInfo(opt.first.c_str(), opt.second)); - } + SmallVector<CheckerOptInfo, 8> checkerOpts = getCheckerOptList(opts); ClangCheckerRegistry allCheckers(plugins, &diags); allCheckers.initializeManager(*checkerMgr, checkerOpts); @@ -137,3 +143,12 @@ void ento::printCheckerHelp(raw_ostream &out, ArrayRef<std::string> plugins) { ClangCheckerRegistry(plugins).printHelp(out); } + +void ento::printEnabledCheckerList(raw_ostream &out, + ArrayRef<std::string> plugins, + const AnalyzerOptions &opts) { + out << "OVERVIEW: Clang Static Analyzer Enabled Checkers List\n\n"; + + SmallVector<CheckerOptInfo, 8> checkerOpts = getCheckerOptList(opts); + ClangCheckerRegistry(plugins).printList(out, checkerOpts); +} diff --git a/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/lib/StaticAnalyzer/Frontend/ModelInjector.cpp index ee2c3f513cdf..0a284851b08d 100644 --- a/lib/StaticAnalyzer/Frontend/ModelInjector.cpp +++ b/lib/StaticAnalyzer/Frontend/ModelInjector.cpp @@ -19,7 +19,6 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/FileSystem.h" -#include <string> #include <utility> using namespace clang; diff --git a/lib/StaticAnalyzer/Frontend/ModelInjector.h b/lib/StaticAnalyzer/Frontend/ModelInjector.h index e23bf8abf384..98a5f69d68e8 100644 --- a/lib/StaticAnalyzer/Frontend/ModelInjector.h +++ b/lib/StaticAnalyzer/Frontend/ModelInjector.h @@ -25,11 +25,7 @@ #define LLVM_CLANG_SA_FRONTEND_MODELINJECTOR_H #include "clang/Analysis/CodeInjector.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringMap.h" -#include <map> -#include <memory> -#include <vector> namespace clang { |