diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/PathDiagnostic.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/PathDiagnostic.cpp | 409 |
1 files changed, 286 insertions, 123 deletions
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 669748c0127ab..1b698ec5c0864 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -1,4 +1,4 @@ -//===--- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -*- C++ -*-===// +//===- PathDiagnostic.cpp - Path-Specific Diagnostic Handling -------------===// // // The LLVM Compiler Infrastructure // @@ -13,26 +13,52 @@ #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/OperationKinds.h" #include "clang/AST/ParentMap.h" -#include "clang/AST/StmtCXX.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Type.h" +#include "clang/Analysis/AnalysisDeclContext.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/ProgramPoint.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <cstring> +#include <memory> +#include <utility> +#include <vector> using namespace clang; using namespace ento; bool PathDiagnosticMacroPiece::containsEvent() const { - for (auto &P : subPieces) { + for (const auto &P : subPieces) { if (isa<PathDiagnosticEventPiece>(*P)) return true; - if (auto *MP = dyn_cast<PathDiagnosticMacroPiece>(P.get())) + if (const auto *MP = dyn_cast<PathDiagnosticMacroPiece>(P.get())) if (MP->containsEvent()) return true; } @@ -43,23 +69,27 @@ static StringRef StripTrailingDots(StringRef s) { for (StringRef::size_type i = s.size(); i != 0; --i) if (s[i - 1] != '.') return s.substr(0, i); - return ""; + return {}; } PathDiagnosticPiece::PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint) - : str(StripTrailingDots(s)), kind(k), Hint(hint), - LastInMainSourceFile(false) {} + : str(StripTrailingDots(s)), kind(k), Hint(hint) {} PathDiagnosticPiece::PathDiagnosticPiece(Kind k, DisplayHint hint) - : kind(k), Hint(hint), LastInMainSourceFile(false) {} + : kind(k), Hint(hint) {} -PathDiagnosticPiece::~PathDiagnosticPiece() {} -PathDiagnosticEventPiece::~PathDiagnosticEventPiece() {} -PathDiagnosticCallPiece::~PathDiagnosticCallPiece() {} -PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() {} -PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() {} -PathDiagnosticNotePiece::~PathDiagnosticNotePiece() {} +PathDiagnosticPiece::~PathDiagnosticPiece() = default; + +PathDiagnosticEventPiece::~PathDiagnosticEventPiece() = default; + +PathDiagnosticCallPiece::~PathDiagnosticCallPiece() = default; + +PathDiagnosticControlFlowPiece::~PathDiagnosticControlFlowPiece() = default; + +PathDiagnosticMacroPiece::~PathDiagnosticMacroPiece() = default; + +PathDiagnosticNotePiece::~PathDiagnosticNotePiece() = default; void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, bool ShouldFlattenMacros) const { @@ -96,22 +126,20 @@ void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, } } -PathDiagnostic::~PathDiagnostic() {} - -PathDiagnostic::PathDiagnostic(StringRef CheckName, const Decl *declWithIssue, - StringRef bugtype, StringRef verboseDesc, - StringRef shortDesc, StringRef category, - PathDiagnosticLocation LocationToUnique, - const Decl *DeclToUnique) - : CheckName(CheckName), - DeclWithIssue(declWithIssue), - BugType(StripTrailingDots(bugtype)), - VerboseDesc(StripTrailingDots(verboseDesc)), - ShortDesc(StripTrailingDots(shortDesc)), - Category(StripTrailingDots(category)), - UniqueingLoc(LocationToUnique), - UniqueingDecl(DeclToUnique), - path(pathImpl) {} +PathDiagnostic::~PathDiagnostic() = default; + +PathDiagnostic::PathDiagnostic( + StringRef CheckName, const Decl *declWithIssue, StringRef bugtype, + StringRef verboseDesc, StringRef shortDesc, StringRef category, + PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique, + std::unique_ptr<FilesToLineNumsMap> ExecutedLines) + : CheckName(CheckName), DeclWithIssue(declWithIssue), + BugType(StripTrailingDots(bugtype)), + VerboseDesc(StripTrailingDots(verboseDesc)), + ShortDesc(StripTrailingDots(shortDesc)), + Category(StripTrailingDots(category)), UniqueingLoc(LocationToUnique), + UniqueingDecl(DeclToUnique), ExecutedLines(std::move(ExecutedLines)), + path(pathImpl) {} static PathDiagnosticCallPiece * getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, @@ -122,11 +150,11 @@ getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, if (CallLoc.isMacroID()) return nullptr; - assert(SMgr.isInMainFile(CallLoc) && - "The call piece should be in the main file."); + assert(AnalysisManager::isInCodeFile(CallLoc, SMgr) && + "The call piece should not be in a header file."); // Check if CP represents a path through a function outside of the main file. - if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation())) + if (!AnalysisManager::isInCodeFile(CP->callEnterWithin.asLocation(), SMgr)) return CP; const PathPieces &Path = CP->path; @@ -135,10 +163,8 @@ getFirstStackedCallToHeaderFile(PathDiagnosticCallPiece *CP, // Check if the last piece in the callee path is a call to a function outside // of the main file. - if (PathDiagnosticCallPiece *CPInner = - dyn_cast<PathDiagnosticCallPiece>(Path.back().get())) { + if (auto *CPInner = dyn_cast<PathDiagnosticCallPiece>(Path.back().get())) return getFirstStackedCallToHeaderFile(CPInner, SMgr); - } // Otherwise, the last piece is in the main file. return nullptr; @@ -154,14 +180,14 @@ void PathDiagnostic::resetDiagnosticLocationToMainFile() { // We only need to check if the report ends inside headers, if the last piece // is a call piece. - if (PathDiagnosticCallPiece *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) { + if (auto *CP = dyn_cast<PathDiagnosticCallPiece>(LastP)) { CP = getFirstStackedCallToHeaderFile(CP, SMgr); if (CP) { // Mark the piece. CP->setAsLastInMainSourceFile(); // Update the path diagnostic message. - const NamedDecl *ND = dyn_cast<NamedDecl>(CP->getCallee()); + const auto *ND = dyn_cast<NamedDecl>(CP->getCallee()); if (ND) { SmallString<200> buf; llvm::raw_svector_ostream os(buf); @@ -178,14 +204,12 @@ void PathDiagnostic::resetDiagnosticLocationToMainFile() { } } -void PathDiagnosticConsumer::anchor() { } +void PathDiagnosticConsumer::anchor() {} PathDiagnosticConsumer::~PathDiagnosticConsumer() { // Delete the contents of the FoldingSet if it isn't empty already. - for (llvm::FoldingSet<PathDiagnostic>::iterator it = - Diags.begin(), et = Diags.end() ; it != et ; ++it) { - delete &*it; - } + for (auto &Diag : Diags) + delete &Diag; } void PathDiagnosticConsumer::HandlePathDiagnostic( @@ -216,9 +240,8 @@ void PathDiagnosticConsumer::HandlePathDiagnostic( while (!WorkList.empty()) { const PathPieces &path = *WorkList.pop_back_val(); - for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; - ++I) { - const PathDiagnosticPiece *piece = I->get(); + for (const auto &I : path) { + const PathDiagnosticPiece *piece = I.get(); FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); if (FID.isInvalid()) { @@ -230,28 +253,23 @@ void PathDiagnosticConsumer::HandlePathDiagnostic( // Check the source ranges. ArrayRef<SourceRange> Ranges = piece->getRanges(); - for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), - E = Ranges.end(); I != E; ++I) { - SourceLocation L = SMgr.getExpansionLoc(I->getBegin()); + for (const auto &I : Ranges) { + SourceLocation L = SMgr.getExpansionLoc(I.getBegin()); if (!L.isFileID() || SMgr.getFileID(L) != FID) { llvm::errs() << warning.str(); return; } - L = SMgr.getExpansionLoc(I->getEnd()); + L = SMgr.getExpansionLoc(I.getEnd()); if (!L.isFileID() || SMgr.getFileID(L) != FID) { llvm::errs() << warning.str(); return; } } - if (const PathDiagnosticCallPiece *call = - dyn_cast<PathDiagnosticCallPiece>(piece)) { + if (const auto *call = dyn_cast<PathDiagnosticCallPiece>(piece)) WorkList.push_back(&call->path); - } - else if (const PathDiagnosticMacroPiece *macro = - dyn_cast<PathDiagnosticMacroPiece>(piece)) { + else if (const auto *macro = dyn_cast<PathDiagnosticMacroPiece>(piece)) WorkList.push_back(¯o->subPieces); - } } } @@ -381,11 +399,29 @@ static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { return None; } +static bool compareCrossTUSourceLocs(FullSourceLoc XL, FullSourceLoc YL) { + std::pair<FileID, unsigned> XOffs = XL.getDecomposedLoc(); + std::pair<FileID, unsigned> YOffs = YL.getDecomposedLoc(); + const SourceManager &SM = XL.getManager(); + std::pair<bool, bool> InSameTU = SM.isInTheSameTranslationUnit(XOffs, YOffs); + if (InSameTU.first) + return XL.isBeforeInTranslationUnitThan(YL); + const FileEntry *XFE = SM.getFileEntryForID(XL.getSpellingLoc().getFileID()); + const FileEntry *YFE = SM.getFileEntryForID(YL.getSpellingLoc().getFileID()); + if (!XFE || !YFE) + return XFE && !YFE; + int NameCmp = XFE->getName().compare(YFE->getName()); + if (NameCmp != 0) + return NameCmp == -1; + // Last resort: Compare raw file IDs that are possibly expansions. + return XL.getFileID() < YL.getFileID(); +} + static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { FullSourceLoc XL = X.getLocation().asLocation(); FullSourceLoc YL = Y.getLocation().asLocation(); if (XL != YL) - return XL.isBeforeInTranslationUnitThan(YL); + return compareCrossTUSourceLocs(XL, YL); if (X.getBugType() != Y.getBugType()) return X.getBugType() < Y.getBugType(); if (X.getCategory() != Y.getCategory()) @@ -405,7 +441,8 @@ static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { SourceLocation YDL = YD->getLocation(); if (XDL != YDL) { const SourceManager &SM = XL.getManager(); - return SM.isBeforeInTranslationUnit(XDL, YDL); + return compareCrossTUSourceLocs(FullSourceLoc(XDL, SM), + FullSourceLoc(YDL, SM)); } } PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end(); @@ -429,11 +466,8 @@ void PathDiagnosticConsumer::FlushDiagnostics( flushed = true; std::vector<const PathDiagnostic *> BatchDiags; - for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(), - et = Diags.end(); it != et; ++it) { - const PathDiagnostic *D = &*it; - BatchDiags.push_back(D); - } + for (const auto &D : Diags) + BatchDiags.push_back(&D); // Sort the diagnostics so that they are always emitted in a deterministic // order. @@ -450,11 +484,8 @@ void PathDiagnosticConsumer::FlushDiagnostics( FlushDiagnosticsImpl(BatchDiags, Files); // Delete the flushed diagnostics. - for (std::vector<const PathDiagnostic *>::iterator it = BatchDiags.begin(), - et = BatchDiags.end(); it != et; ++it) { - const PathDiagnostic *D = *it; + for (const auto D : BatchDiags) delete D; - } // Clear out the FoldingSet. Diags.clear(); @@ -553,6 +584,8 @@ getLocationForCaller(const StackFrameContext *SFC, switch (Source.getKind()) { case CFGElement::Statement: + case CFGElement::Constructor: + case CFGElement::CXXRecordTypedCall: return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), SM, CallerCtx); case CFGElement::Initializer: { @@ -576,8 +609,20 @@ getLocationForCaller(const StackFrameContext *SFC, return PathDiagnosticLocation::createEnd(CallerBody, SM, CallerCtx); return PathDiagnosticLocation::create(CallerInfo->getDecl(), SM); } - case CFGElement::TemporaryDtor: - case CFGElement::NewAllocator: + case CFGElement::NewAllocator: { + const CFGNewAllocator &Alloc = Source.castAs<CFGNewAllocator>(); + return PathDiagnosticLocation(Alloc.getAllocatorExpr(), SM, CallerCtx); + } + case CFGElement::TemporaryDtor: { + // Temporary destructors are for temporaries. They die immediately at around + // the location of CXXBindTemporaryExpr. If they are lifetime-extended, + // they'd be dealt with via an AutomaticObjectDtor instead. + const auto &Dtor = Source.castAs<CFGTemporaryDtor>(); + return PathDiagnosticLocation::createEnd(Dtor.getBindTemporaryExpr(), SM, + CallerCtx); + } + case CFGElement::ScopeBegin: + case CFGElement::ScopeEnd: llvm_unreachable("not yet implemented!"); case CFGElement::LifetimeEnds: case CFGElement::LoopExit: @@ -605,7 +650,7 @@ PathDiagnosticLocation PathDiagnosticLocation::createEnd(const Stmt *S, const SourceManager &SM, LocationOrAnalysisDeclContext LAC) { - if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) + if (const auto *CS = dyn_cast<CompoundStmt>(S)) return createEndBrace(CS, SM); return PathDiagnosticLocation(getValidSourceLocation(S, LAC, /*End=*/true), SM, SingleLocK); @@ -624,7 +669,6 @@ PathDiagnosticLocation::createConditionalColonLoc( return PathDiagnosticLocation(CO->getColonLoc(), SM, SingleLocK); } - PathDiagnosticLocation PathDiagnosticLocation::createMemberLoc(const MemberExpr *ME, const SourceManager &SM) { @@ -649,8 +693,7 @@ PathDiagnosticLocation PathDiagnosticLocation::createDeclBegin(const LocationContext *LC, const SourceManager &SM) { // FIXME: Should handle CXXTryStmt if analyser starts supporting C++. - if (const CompoundStmt *CS = - dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) + if (const auto *CS = dyn_cast_or_null<CompoundStmt>(LC->getDecl()->getBody())) if (!CS->body_empty()) { SourceLocation Loc = (*CS->body_begin())->getLocStart(); return PathDiagnosticLocation(Loc, SM, SingleLocK); @@ -741,6 +784,8 @@ const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { return CEE->getCalleeContext()->getCallSite(); if (Optional<PostInitializer> PIPP = P.getAs<PostInitializer>()) return PIPP->getInitializer()->getInit(); + if (Optional<CallExitBegin> CEB = P.getAs<CallExitBegin>()) + return CEB->getReturnStmt(); return nullptr; } @@ -790,11 +835,11 @@ PathDiagnosticLocation const LocationContext *LC = N->getLocationContext(); // For member expressions, return the location of the '.' or '->'. - if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) + if (const auto *ME = dyn_cast<MemberExpr>(S)) return PathDiagnosticLocation::createMemberLoc(ME, SM); // For binary operators, return the location of the operator. - if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) + if (const auto *B = dyn_cast<BinaryOperator>(S)) return PathDiagnosticLocation::createOperatorLoc(B, SM); if (P.getAs<PostStmtPurgeDeadSymbols>()) @@ -856,7 +901,7 @@ PathDiagnosticRange default: break; case Stmt::DeclStmtClass: { - const DeclStmt *DS = cast<DeclStmt>(S); + const auto *DS = cast<DeclStmt>(S); if (DS->isSingleDecl()) { // Should always be the case, but we'll be defensive. return SourceRange(DS->getLocStart(), @@ -886,9 +931,9 @@ PathDiagnosticRange break; } case DeclK: - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) return MD->getSourceRange(); - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (Stmt *Body = FD->getBody()) return Body->getSourceRange(); } @@ -898,7 +943,7 @@ PathDiagnosticRange } } - return SourceRange(Loc,Loc); + return SourceRange(Loc, Loc); } void PathDiagnosticLocation::flatten() { @@ -954,17 +999,55 @@ void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, // non-autosynthesized callbacks. // Unless set here, the IsCalleeAnAutosynthesizedPropertyAccessor flag // defaults to false. - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(Callee)) + if (const auto *MD = dyn_cast<ObjCMethodDecl>(Callee)) IsCalleeAnAutosynthesizedPropertyAccessor = ( MD->isPropertyAccessor() && CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized()); } -static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D, - StringRef Prefix = StringRef()) { +static void describeTemplateParameters(raw_ostream &Out, + const ArrayRef<TemplateArgument> TAList, + const LangOptions &LO, + StringRef Prefix = StringRef(), + StringRef Postfix = StringRef()); + +static void describeTemplateParameter(raw_ostream &Out, + const TemplateArgument &TArg, + const LangOptions &LO) { + + if (TArg.getKind() == TemplateArgument::ArgKind::Pack) { + describeTemplateParameters(Out, TArg.getPackAsArray(), LO); + } else { + TArg.print(PrintingPolicy(LO), Out); + } +} + +static void describeTemplateParameters(raw_ostream &Out, + const ArrayRef<TemplateArgument> TAList, + const LangOptions &LO, + StringRef Prefix, StringRef Postfix) { + if (TAList.empty()) + return; + + Out << Prefix; + for (int I = 0, Last = TAList.size() - 1; I != Last; ++I) { + describeTemplateParameter(Out, TAList[I], LO); + Out << ", "; + } + describeTemplateParameter(Out, TAList[TAList.size() - 1], LO); + Out << Postfix; +} + +static void describeClass(raw_ostream &Out, const CXXRecordDecl *D, + StringRef Prefix = StringRef()) { if (!D->getIdentifier()) return; - Out << Prefix << '\'' << *D << '\''; + Out << Prefix << '\'' << *D; + if (const auto T = dyn_cast<ClassTemplateSpecializationDecl>(D)) + describeTemplateParameters(Out, T->getTemplateArgs().asArray(), + D->getASTContext().getLangOpts(), "<", ">"); + + Out << '\''; } static bool describeCodeDecl(raw_ostream &Out, const Decl *D, @@ -979,7 +1062,7 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D, return ExtendedDescription; } - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { + if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { Out << Prefix; if (ExtendedDescription && !MD->isUserProvided()) { if (MD->isExplicitlyDefaulted()) @@ -988,7 +1071,7 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D, Out << "implicit "; } - if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) { + if (const auto *CD = dyn_cast<CXXConstructorDecl>(MD)) { if (CD->isDefaultConstructor()) Out << "default "; else if (CD->isCopyConstructor()) @@ -998,7 +1081,6 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D, Out << "constructor"; describeClass(Out, MD->getParent(), " for "); - } else if (isa<CXXDestructorDecl>(MD)) { if (!MD->isUserProvided()) { Out << "destructor"; @@ -1007,15 +1089,12 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D, // Use ~Foo for explicitly-written destructors. Out << "'" << *MD << "'"; } - } else if (MD->isCopyAssignmentOperator()) { Out << "copy assignment operator"; describeClass(Out, MD->getParent(), " for "); - } else if (MD->isMoveAssignmentOperator()) { Out << "move assignment operator"; describeClass(Out, MD->getParent(), " for "); - } else { if (MD->getParent()->getIdentifier()) Out << "'" << *MD->getParent() << "::" << *MD << "'"; @@ -1026,7 +1105,16 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D, return true; } - Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\''; + Out << Prefix << '\'' << cast<NamedDecl>(*D); + + // Adding template parameters. + if (const auto FD = dyn_cast<FunctionDecl>(D)) + if (const TemplateArgumentList *TAList = + FD->getTemplateSpecializationArgs()) + describeTemplateParameters(Out, TAList->asArray(), + FD->getASTContext().getLangOpts(), "<", ">"); + + Out << '\''; return true; } @@ -1055,7 +1143,7 @@ PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { return nullptr; if (Callee->isImplicit() || !Callee->hasBody()) return nullptr; - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee)) + if (const auto *MD = dyn_cast<CXXMethodDecl>(Callee)) if (MD->isDefaulted()) return nullptr; @@ -1095,13 +1183,10 @@ PathDiagnosticCallPiece::getCallExitEvent() const { } static void compute_path_size(const PathPieces &pieces, unsigned &size) { - for (PathPieces::const_iterator it = pieces.begin(), - et = pieces.end(); it != et; ++it) { - const PathDiagnosticPiece *piece = it->get(); - if (const PathDiagnosticCallPiece *cp = - dyn_cast<PathDiagnosticCallPiece>(piece)) { + for (const auto &I : pieces) { + const PathDiagnosticPiece *piece = I.get(); + if (const auto *cp = dyn_cast<PathDiagnosticCallPiece>(piece)) compute_path_size(cp->path, size); - } else ++size; } @@ -1129,19 +1214,16 @@ void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const { // FIXME: Add profiling support for code hints. ID.AddInteger((unsigned) getDisplayHint()); ArrayRef<SourceRange> Ranges = getRanges(); - for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); - I != E; ++I) { - ID.AddInteger(I->getBegin().getRawEncoding()); - ID.AddInteger(I->getEnd().getRawEncoding()); + for (const auto &I : Ranges) { + ID.AddInteger(I.getBegin().getRawEncoding()); + ID.AddInteger(I.getEnd().getRawEncoding()); } } void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { PathDiagnosticPiece::Profile(ID); - for (PathPieces::const_iterator it = path.begin(), - et = path.end(); it != et; ++it) { - ID.Add(**it); - } + for (const auto &I : path) + ID.Add(*I); } void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { @@ -1151,15 +1233,14 @@ void PathDiagnosticSpotPiece::Profile(llvm::FoldingSetNodeID &ID) const { void PathDiagnosticControlFlowPiece::Profile(llvm::FoldingSetNodeID &ID) const { PathDiagnosticPiece::Profile(ID); - for (const_iterator I = begin(), E = end(); I != E; ++I) - ID.Add(*I); + for (const auto &I : *this) + ID.Add(I); } void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { PathDiagnosticSpotPiece::Profile(ID); - for (PathPieces::const_iterator I = subPieces.begin(), E = subPieces.end(); - I != E; ++I) - ID.Add(**I); + for (const auto &I : subPieces) + ID.Add(*I); } void PathDiagnosticNotePiece::Profile(llvm::FoldingSetNodeID &ID) const { @@ -1175,34 +1256,32 @@ void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { void PathDiagnostic::FullProfile(llvm::FoldingSetNodeID &ID) const { Profile(ID); - for (PathPieces::const_iterator I = path.begin(), E = path.end(); I != E; ++I) - ID.Add(**I); + for (const auto &I : path) + ID.Add(*I); for (meta_iterator I = meta_begin(), E = meta_end(); I != E; ++I) ID.AddString(*I); } -StackHintGenerator::~StackHintGenerator() {} +StackHintGenerator::~StackHintGenerator() = default; std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ + if (!N) + return getMessageForSymbolNotFound(); + ProgramPoint P = N->getLocation(); CallExitEnd CExit = P.castAs<CallExitEnd>(); // FIXME: Use CallEvent to abstract this over all calls. const Stmt *CallSite = CExit.getCalleeContext()->getCallSite(); - const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite); + const auto *CE = dyn_cast_or_null<CallExpr>(CallSite); if (!CE) - return ""; - - if (!N) - return getMessageForSymbolNotFound(); + return {}; // Check if one of the parameters are set to the interesting symbol. - ProgramStateRef State = N->getState(); - const LocationContext *LCtx = N->getLocationContext(); unsigned ArgIndex = 0; for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); I != E; ++I, ++ArgIndex){ - SVal SV = State->getSVal(*I, LCtx); + SVal SV = N->getSVal(*I); // Check if the variable corresponding to the symbol is passed by value. SymbolRef AS = SV.getAsLocSymbol(); @@ -1212,7 +1291,10 @@ std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ // Check if the parameter is a pointer to the symbol. if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) { - SVal PSV = State->getSVal(Reg->getRegion()); + // Do not attempt to dereference void*. + if ((*I)->getType()->isVoidPointerType()) + continue; + SVal PSV = N->getState()->getSVal(Reg->getRegion()); SymbolRef AS = PSV.getAsLocSymbol(); if (AS == Sym) { return getMessageForArg(*I, ArgIndex); @@ -1221,7 +1303,7 @@ std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ } // Check if we are returning the interesting symbol. - SVal SV = State->getSVal(CE, LCtx); + SVal SV = N->getSVal(CE); SymbolRef RetSym = SV.getAsLocSymbol(); if (RetSym == Sym) { return getMessageForReturn(CE); @@ -1243,3 +1325,84 @@ std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE, return os.str(); } + +LLVM_DUMP_METHOD void PathPieces::dump() const { + unsigned index = 0; + for (PathPieces::const_iterator I = begin(), E = end(); I != E; ++I) { + llvm::errs() << "[" << index++ << "] "; + (*I)->dump(); + llvm::errs() << "\n"; + } +} + +LLVM_DUMP_METHOD void PathDiagnosticCallPiece::dump() const { + llvm::errs() << "CALL\n--------------\n"; + + if (const Stmt *SLoc = getLocation().getStmtOrNull()) + SLoc->dump(); + else if (const auto *ND = dyn_cast_or_null<NamedDecl>(getCallee())) + llvm::errs() << *ND << "\n"; + else + getLocation().dump(); +} + +LLVM_DUMP_METHOD void PathDiagnosticEventPiece::dump() const { + llvm::errs() << "EVENT\n--------------\n"; + llvm::errs() << getString() << "\n"; + llvm::errs() << " ---- at ----\n"; + getLocation().dump(); +} + +LLVM_DUMP_METHOD void PathDiagnosticControlFlowPiece::dump() const { + llvm::errs() << "CONTROL\n--------------\n"; + getStartLocation().dump(); + llvm::errs() << " ---- to ----\n"; + getEndLocation().dump(); +} + +LLVM_DUMP_METHOD void PathDiagnosticMacroPiece::dump() const { + llvm::errs() << "MACRO\n--------------\n"; + // FIXME: Print which macro is being invoked. +} + +LLVM_DUMP_METHOD void PathDiagnosticNotePiece::dump() const { + llvm::errs() << "NOTE\n--------------\n"; + llvm::errs() << getString() << "\n"; + llvm::errs() << " ---- at ----\n"; + getLocation().dump(); +} + +LLVM_DUMP_METHOD void PathDiagnosticLocation::dump() const { + if (!isValid()) { + llvm::errs() << "<INVALID>\n"; + return; + } + + switch (K) { + case RangeK: + // FIXME: actually print the range. + llvm::errs() << "<range>\n"; + break; + case SingleLocK: + asLocation().dump(); + llvm::errs() << "\n"; + break; + case StmtK: + if (S) + S->dump(); + else + llvm::errs() << "<NULL STMT>\n"; + break; + case DeclK: + if (const auto *ND = dyn_cast_or_null<NamedDecl>(D)) + llvm::errs() << *ND << "\n"; + else if (isa<BlockDecl>(D)) + // FIXME: Make this nicer. + llvm::errs() << "<block>\n"; + else if (D) + llvm::errs() << "<unknown decl>\n"; + else + llvm::errs() << "<NULL DECL>\n"; + break; + } +} |