diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp | 136 |
1 files changed, 107 insertions, 29 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp index 1ef70b650414e..528f68c6c429d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp @@ -106,7 +106,7 @@ static const NoteTag *getNoteTag(CheckerContext &C, QualType CastToTy, const Expr *Object, bool CastSucceeds, bool IsKnownCast) { std::string CastToName = - CastInfo ? CastInfo->to()->getPointeeCXXRecordDecl()->getNameAsString() + CastInfo ? CastInfo->to()->getAsCXXRecordDecl()->getNameAsString() : CastToTy->getPointeeCXXRecordDecl()->getNameAsString(); Object = Object->IgnoreParenImpCasts(); @@ -135,6 +135,47 @@ static const NoteTag *getNoteTag(CheckerContext &C, /*IsPrunable=*/true); } +static const NoteTag *getNoteTag(CheckerContext &C, + SmallVector<QualType, 4> CastToTyVec, + const Expr *Object, + bool IsKnownCast) { + Object = Object->IgnoreParenImpCasts(); + + return C.getNoteTag( + [=]() -> std::string { + SmallString<128> Msg; + llvm::raw_svector_ostream Out(Msg); + + if (!IsKnownCast) + Out << "Assuming "; + + if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) { + Out << '\'' << DRE->getDecl()->getNameAsString() << '\''; + } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) { + Out << (IsKnownCast ? "Field '" : "field '") + << ME->getMemberDecl()->getNameAsString() << '\''; + } else { + Out << (IsKnownCast ? "The object" : "the object"); + } + Out << " is"; + + bool First = true; + for (QualType CastToTy: CastToTyVec) { + std::string CastToName = + CastToTy->getAsCXXRecordDecl() ? + CastToTy->getAsCXXRecordDecl()->getNameAsString() : + CastToTy->getPointeeCXXRecordDecl()->getNameAsString(); + Out << ' ' << ((CastToTyVec.size() == 1) ? "not" : + (First ? "neither" : "nor")) << " a '" << CastToName + << '\''; + First = false; + } + + return std::string(Out.str()); + }, + /*IsPrunable=*/true); +} + //===----------------------------------------------------------------------===// // Main logic to evaluate a cast. //===----------------------------------------------------------------------===// @@ -220,40 +261,76 @@ static void addInstanceOfTransition(const CallEvent &Call, bool IsInstanceOf) { const FunctionDecl *FD = Call.getDecl()->getAsFunction(); QualType CastFromTy = Call.parameters()[0]->getType(); - QualType CastToTy = FD->getTemplateSpecializationArgs()->get(0).getAsType(); - if (CastFromTy->isPointerType()) - CastToTy = C.getASTContext().getPointerType(CastToTy); - else if (CastFromTy->isReferenceType()) - CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext()); - else - return; + SmallVector<QualType, 4> CastToTyVec; + for (unsigned idx = 0; idx < FD->getTemplateSpecializationArgs()->size() - 1; + ++idx) { + TemplateArgument CastToTempArg = + FD->getTemplateSpecializationArgs()->get(idx); + switch (CastToTempArg.getKind()) { + default: + return; + case TemplateArgument::Type: + CastToTyVec.push_back(CastToTempArg.getAsType()); + break; + case TemplateArgument::Pack: + for (TemplateArgument ArgInPack: CastToTempArg.pack_elements()) + CastToTyVec.push_back(ArgInPack.getAsType()); + break; + } + } const MemRegion *MR = DV.getAsRegion(); - const DynamicCastInfo *CastInfo = + if (MR && CastFromTy->isReferenceType()) + MR = State->getSVal(DV.castAs<Loc>()).getAsRegion(); + + bool Success = false; + bool IsAnyKnown = false; + for (QualType CastToTy: CastToTyVec) { + if (CastFromTy->isPointerType()) + CastToTy = C.getASTContext().getPointerType(CastToTy); + else if (CastFromTy->isReferenceType()) + CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext()); + else + return; + + const DynamicCastInfo *CastInfo = getDynamicCastInfo(State, MR, CastFromTy, CastToTy); - bool CastSucceeds; - if (CastInfo) - CastSucceeds = IsInstanceOf && CastInfo->succeeds(); - else - CastSucceeds = IsInstanceOf || CastFromTy == CastToTy; + bool CastSucceeds; + if (CastInfo) + CastSucceeds = IsInstanceOf && CastInfo->succeeds(); + else + CastSucceeds = IsInstanceOf || CastFromTy == CastToTy; + + // Store the type and the cast information. + bool IsKnownCast = CastInfo || CastFromTy == CastToTy; + IsAnyKnown = IsAnyKnown || IsKnownCast; + ProgramStateRef NewState = State; + if (!IsKnownCast) + NewState = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy, + IsInstanceOf); - if (isInfeasibleCast(CastInfo, CastSucceeds)) { - C.generateSink(State, C.getPredecessor()); - return; + if (CastSucceeds) { + Success = true; + C.addTransition( + NewState->BindExpr(Call.getOriginExpr(), C.getLocationContext(), + C.getSValBuilder().makeTruthVal(true)), + getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), true, + IsKnownCast)); + if (IsKnownCast) + return; + } else if (CastInfo && CastInfo->succeeds()) { + C.generateSink(NewState, C.getPredecessor()); + return; + } } - // Store the type and the cast information. - bool IsKnownCast = CastInfo || CastFromTy == CastToTy; - if (!IsKnownCast) - State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy, - IsInstanceOf); - - C.addTransition( - State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), - C.getSValBuilder().makeTruthVal(CastSucceeds)), - getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), CastSucceeds, - IsKnownCast)); + if (!Success) { + C.addTransition( + State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), + C.getSValBuilder().makeTruthVal(false)), + getNoteTag(C, CastToTyVec, Call.getArgExpr(0), IsAnyKnown)); + } } //===----------------------------------------------------------------------===// @@ -402,8 +479,9 @@ bool CastValueChecker::evalCall(const CallEvent &Call, QualType ParamT = Call.parameters()[0]->getType(); QualType ResultT = Call.getResultType(); if (!(ParamT->isPointerType() && ResultT->isPointerType()) && - !(ParamT->isReferenceType() && ResultT->isReferenceType())) + !(ParamT->isReferenceType() && ResultT->isReferenceType())) { return false; + } DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>(); break; |
