diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/PathDiagnostic.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/PathDiagnostic.cpp | 219 |
1 files changed, 151 insertions, 68 deletions
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 0f48d1e1c798..7c0fb14a5c82 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -12,16 +12,17 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" -#include "clang/Basic/SourceManager.h" -#include "clang/AST/Expr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtCXX.h" +#include "clang/Basic/SourceManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace ento; @@ -106,12 +107,16 @@ PathDiagnostic::~PathDiagnostic() {} PathDiagnostic::PathDiagnostic(const Decl *declWithIssue, StringRef bugtype, StringRef verboseDesc, - StringRef shortDesc, StringRef category) + StringRef shortDesc, StringRef category, + PathDiagnosticLocation LocationToUnique, + const Decl *DeclToUnique) : DeclWithIssue(declWithIssue), BugType(StripTrailingDots(bugtype)), VerboseDesc(StripTrailingDots(verboseDesc)), ShortDesc(StripTrailingDots(shortDesc)), Category(StripTrailingDots(category)), + UniqueingLoc(LocationToUnique), + UniqueingDecl(DeclToUnique), path(pathImpl) {} void PathDiagnosticConsumer::anchor() { } @@ -125,7 +130,7 @@ PathDiagnosticConsumer::~PathDiagnosticConsumer() { } void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { - llvm::OwningPtr<PathDiagnostic> OwningD(D); + OwningPtr<PathDiagnostic> OwningD(D); if (!D || D->path.empty()) return; @@ -141,7 +146,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { // Verify that the entire path is from the same FileID. FileID FID; const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager(); - llvm::SmallVector<const PathPieces *, 5> WorkList; + SmallVector<const PathPieces *, 5> WorkList; WorkList.push_back(&D->path); while (!WorkList.empty()) { @@ -208,9 +213,8 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { Diags.InsertNode(OwningD.take()); } -static llvm::Optional<bool> comparePath(const PathPieces &X, - const PathPieces &Y); -static llvm::Optional<bool> +static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y); +static Optional<bool> compareControlFlow(const PathDiagnosticControlFlowPiece &X, const PathDiagnosticControlFlowPiece &Y) { FullSourceLoc XSL = X.getStartLocation().asLocation(); @@ -221,18 +225,16 @@ compareControlFlow(const PathDiagnosticControlFlowPiece &X, FullSourceLoc YEL = Y.getEndLocation().asLocation(); if (XEL != YEL) return XEL.isBeforeInTranslationUnitThan(YEL); - return llvm::Optional<bool>(); + return None; } -static llvm::Optional<bool> -compareMacro(const PathDiagnosticMacroPiece &X, - const PathDiagnosticMacroPiece &Y) { +static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X, + const PathDiagnosticMacroPiece &Y) { return comparePath(X.subPieces, Y.subPieces); } -static llvm::Optional<bool> -compareCall(const PathDiagnosticCallPiece &X, - const PathDiagnosticCallPiece &Y) { +static Optional<bool> compareCall(const PathDiagnosticCallPiece &X, + const PathDiagnosticCallPiece &Y) { FullSourceLoc X_CEL = X.callEnter.asLocation(); FullSourceLoc Y_CEL = Y.callEnter.asLocation(); if (X_CEL != Y_CEL) @@ -248,8 +250,8 @@ compareCall(const PathDiagnosticCallPiece &X, return comparePath(X.path, Y.path); } -static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X, - const PathDiagnosticPiece &Y) { +static Optional<bool> comparePiece(const PathDiagnosticPiece &X, + const PathDiagnosticPiece &Y) { if (X.getKind() != Y.getKind()) return X.getKind() < Y.getKind(); @@ -281,7 +283,7 @@ static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X, return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), cast<PathDiagnosticControlFlowPiece>(Y)); case clang::ento::PathDiagnosticPiece::Event: - return llvm::Optional<bool>(); + return None; case clang::ento::PathDiagnosticPiece::Macro: return compareMacro(cast<PathDiagnosticMacroPiece>(X), cast<PathDiagnosticMacroPiece>(Y)); @@ -292,16 +294,15 @@ static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X, llvm_unreachable("all cases handled"); } -static llvm::Optional<bool> comparePath(const PathPieces &X, - const PathPieces &Y) { +static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) { if (X.size() != Y.size()) return X.size() < Y.size(); for (unsigned i = 0, n = X.size(); i != n; ++i) { - llvm::Optional<bool> b = comparePiece(*X[i], *Y[i]); + Optional<bool> b = comparePiece(*X[i], *Y[i]); if (b.hasValue()) return b.getValue(); } - return llvm::Optional<bool>(); + return None; } static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { @@ -339,7 +340,7 @@ static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { if (*XI != *YI) return (*XI) < (*YI); } - llvm::Optional<bool> b = comparePath(X.path, Y.path); + Optional<bool> b = comparePath(X.path, Y.path); assert(b.hasValue()); return b.getValue(); } @@ -475,18 +476,16 @@ getLocationForCaller(const StackFrameContext *SFC, CFGElement Source = Block[SFC->getIndex()]; switch (Source.getKind()) { - case CFGElement::Invalid: - llvm_unreachable("Invalid CFGElement"); case CFGElement::Statement: - return PathDiagnosticLocation(cast<CFGStmt>(Source).getStmt(), + return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(), SM, CallerCtx); case CFGElement::Initializer: { - const CFGInitializer &Init = cast<CFGInitializer>(Source); + const CFGInitializer &Init = Source.castAs<CFGInitializer>(); return PathDiagnosticLocation(Init.getInitializer()->getInit(), SM, CallerCtx); } case CFGElement::AutomaticObjectDtor: { - const CFGAutomaticObjDtor &Dtor = cast<CFGAutomaticObjDtor>(Source); + const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>(); return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(), SM, CallerCtx); } @@ -582,27 +581,27 @@ PathDiagnosticLocation const SourceManager &SMng) { const Stmt* S = 0; - if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { + if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { const CFGBlock *BSrc = BE->getSrc(); S = BSrc->getTerminatorCondition(); - } - else if (const StmtPoint *SP = dyn_cast<StmtPoint>(&P)) { + } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) { S = SP->getStmt(); - } - else if (const PostImplicitCall *PIE = dyn_cast<PostImplicitCall>(&P)) { + if (P.getAs<PostStmtPurgeDeadSymbols>()) + return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext()); + } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) { + return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(), + SMng); + } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) { return PathDiagnosticLocation(PIE->getLocation(), SMng); - } - else if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) { + } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { return getLocationForCaller(CE->getCalleeContext(), CE->getLocationContext(), SMng); - } - else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&P)) { + } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) { return getLocationForCaller(CEE->getCalleeContext(), CEE->getLocationContext(), SMng); - } - else { + } else { llvm_unreachable("Unexpected ProgramPoint"); } @@ -619,12 +618,16 @@ PathDiagnosticLocation while (NI) { ProgramPoint P = NI->getLocation(); - if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P)) + if (Optional<StmtPoint> PS = P.getAs<StmtPoint>()) { S = PS->getStmt(); - else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) + if (P.getAs<PostStmtPurgeDeadSymbols>()) + return PathDiagnosticLocation::createEnd(S, SM, + NI->getLocationContext()); + break; + } else if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) { S = BE->getSrc()->getTerminator(); - if (S) break; + } NI = NI->succ_empty() ? 0 : *(NI->succ_begin()); } @@ -777,48 +780,129 @@ void PathDiagnosticCallPiece::setCallee(const CallEnter &CE, callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); } +static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D, + StringRef Prefix = StringRef()) { + if (!D->getIdentifier()) + return; + Out << Prefix << '\'' << *D << '\''; +} + +static bool describeCodeDecl(raw_ostream &Out, const Decl *D, + bool ExtendedDescription, + StringRef Prefix = StringRef()) { + if (!D) + return false; + + if (isa<BlockDecl>(D)) { + if (ExtendedDescription) + Out << Prefix << "anonymous block"; + return ExtendedDescription; + } + + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { + Out << Prefix; + if (ExtendedDescription && !MD->isUserProvided()) { + if (MD->isExplicitlyDefaulted()) + Out << "defaulted "; + else + Out << "implicit "; + } + + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) { + if (CD->isDefaultConstructor()) + Out << "default "; + else if (CD->isCopyConstructor()) + Out << "copy "; + else if (CD->isMoveConstructor()) + Out << "move "; + + Out << "constructor"; + describeClass(Out, MD->getParent(), " for "); + + } else if (isa<CXXDestructorDecl>(MD)) { + if (!MD->isUserProvided()) { + Out << "destructor"; + describeClass(Out, MD->getParent(), " for "); + } else { + // 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 << "'"; + else + Out << "'" << *MD << "'"; + } + + return true; + } + + Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\''; + return true; +} + IntrusiveRefCntPtr<PathDiagnosticEventPiece> PathDiagnosticCallPiece::getCallEnterEvent() const { if (!Callee) return 0; + SmallString<256> buf; llvm::raw_svector_ostream Out(buf); - if (isa<BlockDecl>(Callee)) - Out << "Calling anonymous block"; - else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee)) - Out << "Calling '" << *ND << "'"; - StringRef msg = Out.str(); - if (msg.empty()) - return 0; - return new PathDiagnosticEventPiece(callEnter, msg); + + Out << "Calling "; + describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true); + + assert(callEnter.asLocation().isValid()); + return new PathDiagnosticEventPiece(callEnter, Out.str()); } IntrusiveRefCntPtr<PathDiagnosticEventPiece> PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const { + if (!callEnterWithin.asLocation().isValid()) + return 0; + if (Callee->isImplicit()) + return 0; + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee)) + if (MD->isDefaulted()) + return 0; + SmallString<256> buf; llvm::raw_svector_ostream Out(buf); - if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller)) - Out << "Entered call from '" << *ND << "'"; - else - Out << "Entered call"; - StringRef msg = Out.str(); - if (msg.empty()) - return 0; - return new PathDiagnosticEventPiece(callEnterWithin, msg); + + Out << "Entered call"; + describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from "); + + return new PathDiagnosticEventPiece(callEnterWithin, Out.str()); } IntrusiveRefCntPtr<PathDiagnosticEventPiece> PathDiagnosticCallPiece::getCallExitEvent() const { if (NoExit) return 0; + SmallString<256> buf; llvm::raw_svector_ostream Out(buf); - if (!CallStackMessage.empty()) + + if (!CallStackMessage.empty()) { Out << CallStackMessage; - else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee)) - Out << "Returning from '" << *ND << "'"; - else - Out << "Returning to caller"; + } else { + bool DidDescribe = describeCodeDecl(Out, Callee, + /*ExtendedDescription=*/false, + "Returning from "); + if (!DidDescribe) + Out << "Returning to caller"; + } + + assert(callReturn.asLocation().isValid()); return new PathDiagnosticEventPiece(callReturn, Out.str()); } @@ -910,11 +994,10 @@ StackHintGenerator::~StackHintGenerator() {} std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ ProgramPoint P = N->getLocation(); - const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P); - assert(CExit && "Stack Hints should be constructed at CallExitEnd points."); + CallExitEnd CExit = P.castAs<CallExitEnd>(); // FIXME: Use CallEvent to abstract this over all calls. - const Stmt *CallSite = CExit->getCalleeContext()->getCallSite(); + const Stmt *CallSite = CExit.getCalleeContext()->getCallSite(); const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite); if (!CE) return ""; @@ -937,7 +1020,7 @@ std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ } // Check if the parameter is a pointer to the symbol. - if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) { + if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) { SVal PSV = State->getSVal(Reg->getRegion()); SymbolRef AS = PSV.getAsLocSymbol(); if (AS == Sym) { |