Index: clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp @@ -168,6 +168,19 @@ if (Call.getNumArgs() > 0) { Object = Call.getArgExpr(0); CastFromTy = Call.parameters()[0]->getType(); + llvm::errs()<<"<<>>\n"; + llvm::errs()<<"CastFromType:\n"; + CastFromTy->dump(); + llvm::errs()<<"\n"; + llvm::errs()<<"Desugared:\n"; + CastFromTy->getUnqualifiedDesugaredType()->dump(); + llvm::errs()<<"\n"; + if (CastFromTy->isPointerType()) { + llvm::errs()<<"Desugared pointer:\n"; + cast(CastFromTy.getTypePtr())->desugar()->dump(); + llvm::errs()<<"\n"; + + } } else { Object = cast(&Call)->getCXXThisExpr(); CastFromTy = Object->getType(); @@ -185,6 +198,8 @@ const MemRegion *MR = DV.getAsRegion(); const DynamicCastInfo *CastInfo = getDynamicCastInfo(State, MR, CastFromTy, CastToTy); + if (CastInfo && CastInfo->succeeds()) llvm::errs()<<" Casting succeeds.\n"; + if (CastInfo && CastInfo->fails()) llvm::errs()<<" Casting fails.\n"; // We assume that every checked cast succeeds. bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy; @@ -198,14 +213,24 @@ // Check for infeasible casts. if (isInfeasibleCast(CastInfo, CastSucceeds)) { C.generateSink(State, C.getPredecessor()); + llvm::errs()<<"Infeasible cast.\n"; return; } // Store the type and the cast information. bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy; - if (!IsKnownCast || IsCheckedCast) + llvm::errs()<<"CastInfo: "<<(CastInfo?"exists":"none")<<"\n"; + llvm::errs()<<"IsCheckedCast: "<<(IsCheckedCast?"true":"false")<<"\n"; + llvm::errs()<<"CastFromTy == CastToTy: "<<((CastFromTy == CastToTy)?"true":"false")<<"\n"; + if (!IsKnownCast || IsCheckedCast) { + llvm::errs()<<"Setting "<<(CastSucceeds?"positive":"negative")<<" dynamic type info for "<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; + llvm::errs()<<"<<>>\n"; + llvm::errs()<<"CastFromType:\n"; + CastFromTy->dump(); + llvm::errs()<<"\n"; + llvm::errs()<<"Desugared:\n"; + CastFromTy->getUnqualifiedDesugaredType()->dump(); + llvm::errs()<<"\n"; + assert(CastFromTy->isReferenceType()); + CastFromTy = CastFromTy.getNonReferenceType(); + llvm::errs()<<"NonRef:\n"; + CastFromTy->dump(); + llvm::errs()<<"\n"; + assert(isa(CastFromTy.getTypePtr())); + CastFromTy = cast( + CastFromTy.getTypePtr())->getReplacementType(); + llvm::errs()<<"Replacement:\n"; + CastFromTy->dump(); + llvm::errs()<<"\n"; + SmallVector CastToTyVec; + for (unsigned idx = 0; idx < FD->getTemplateSpecializationArgs()->size() - 1; + ++idx) { + TemplateArgument CastToTempArg = + FD->getTemplateSpecializationArgs()->get(idx); + switch (CastToTempArg.getKind()) { + default: + llvm_unreachable("Invalid template argument for isa<> or " + "isa_and_nonnull<>"); + case TemplateArgument::Type: + CastToTyVec.push_back(CastToTempArg.getAsType()); + break; + case TemplateArgument::Pack: + for (TemplateArgument ArgInPack: CastToTempArg.pack_elements()) + CastToTyVec.push_back(ArgInPack.getAsType()); + break; + } + } + llvm::errs()<<"Checking instance of: "; + CastFromTy.dump(); + llvm::errs()<<"\n"; const MemRegion *MR = DV.getAsRegion(); - const DynamicCastInfo *CastInfo = - getDynamicCastInfo(State, MR, CastFromTy, CastToTy); + bool Success = false; + for (QualType CastToTy: CastToTyVec) { + llvm::errs()<<"Processing (IsInstanceOf is "<<(IsInstanceOf?"true":"false")<<"): "; + CastToTy.dump(); + llvm::errs()<<"\n"; + if (CastFromTy->isPointerType()) + CastToTy = C.getASTContext().getPointerType(CastToTy); + else if (CastFromTy->isReferenceType()) + CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext()); + else + return; - bool CastSucceeds; - if (CastInfo) - CastSucceeds = IsInstanceOf && CastInfo->succeeds(); - else - CastSucceeds = IsInstanceOf || CastFromTy == CastToTy; + const DynamicCastInfo *CastInfo = + getDynamicCastInfo(State, MR, CastFromTy, CastToTy); + if (CastInfo && CastInfo->succeeds()) llvm::errs()<<" Casting succeeds.\n"; + if (CastInfo && CastInfo->fails()) llvm::errs()<<" Casting fails.\n"; - if (isInfeasibleCast(CastInfo, CastSucceeds)) { - C.generateSink(State, C.getPredecessor()); - return; + bool CastSucceeds; + if (CastInfo) + CastSucceeds = IsInstanceOf && CastInfo->succeeds(); + else + CastSucceeds = IsInstanceOf || CastFromTy == CastToTy; + llvm::errs()<<" CastSucceeds: "<<(CastSucceeds?"true":"false")<<"\n"; + + // Store the type and the cast information. + bool IsKnownCast = CastInfo || CastFromTy == CastToTy; + ProgramStateRef NewState = State; + if (!IsKnownCast) + NewState = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy, + IsInstanceOf); + + 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)); + } 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))); + } } //===----------------------------------------------------------------------===// @@ -402,8 +483,11 @@ QualType ParamT = Call.parameters()[0]->getType(); QualType ResultT = Call.getResultType(); if (!(ParamT->isPointerType() && ResultT->isPointerType()) && - !(ParamT->isReferenceType() && ResultT->isReferenceType())) + !(ParamT->isReferenceType() && ResultT->isReferenceType())) { + llvm::errs()<<"Neither pointer, nor reference:\n"; + Call.dump(); return false; + } DV = Call.getArgSVal(0).getAs(); break; Index: clang/test/Analysis/Inputs/llvm.h =================================================================== --- clang/test/Analysis/Inputs/llvm.h +++ clang/test/Analysis/Inputs/llvm.h @@ -19,11 +19,19 @@ template const X *dyn_cast_or_null(Y &Value); -template -bool isa(Y Value); - -template -bool isa_and_nonnull(Y Value); +template inline bool isa(const Y &Val); + +template +inline bool isa(const Y &Val) { + return isa(Val) || isa(Val); +} + +template +inline bool isa_and_nonnull(const Y &Val) { + if (!Val) + return false; + return isa(Val); +} template std::unique_ptr cast(std::unique_ptr &&Value); Index: clang/test/Analysis/cast-value-logic.cpp =================================================================== --- clang/test/Analysis/cast-value-logic.cpp +++ clang/test/Analysis/cast-value-logic.cpp @@ -19,6 +19,8 @@ virtual double area(); }; class Triangle : public Shape {}; +class Rectangle : public Shape {}; +class Hexagon : public Shape {}; class Circle : public Shape { public: ~Circle(); @@ -39,6 +41,23 @@ clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}} } +void test_regions_isa_variadic(const Shape *A, const Shape *B) { + if (isa(A) && + !isa(B)) + clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}} +} + +void test_regions_isa_and_nonnull(const Shape *A, const Shape *B) { + if (isa_and_nonnull(A) && !isa_and_nonnull(B)) + clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}} +} + +void test_regions_isa_and_nonnull_variadic(const Shape *A, const Shape *B) { + if (isa_and_nonnull(A) && + !isa_and_nonnull(B)) + clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}} +} + namespace test_cast { void evalLogic(const Shape *S) { const Circle *C = cast(S); Index: clang/test/Analysis/cast-value-notes.cpp =================================================================== --- clang/test/Analysis/cast-value-notes.cpp +++ clang/test/Analysis/cast-value-notes.cpp @@ -13,20 +13,22 @@ const T *getAs() const; }; class Triangle : public Shape {}; +class Rectangle : public Shape {}; +class Hexagon : public Shape {}; class Circle : public Shape {}; } // namespace clang using namespace llvm; using namespace clang; -void evalReferences(const Shape &S) { +/*void evalReferences(const Shape &S) { const auto &C = dyn_cast(S); // expected-note@-1 {{Assuming 'S' is not a 'Circle'}} // expected-note@-2 {{Dereference of null pointer}} // expected-warning@-3 {{Dereference of null pointer}} -} + }*/ -void evalNonNullParamNonNullReturnReference(const Shape &S) { +void evalNonNullParamNonNullReturnReference(const Shape *S) { // Unmodeled cast from reference to pointer. const auto *C = dyn_cast_or_null(S); // expected-note@-1 {{'C' initialized here}} @@ -43,12 +45,36 @@ return; } + if (dyn_cast_or_null(C)) { + // expected-note@-1 {{Assuming 'C' is not a 'Rectangle'}} + // expected-note@-2 {{Taking false branch}} + return; + } + + if (dyn_cast_or_null(C)) { + // expected-note@-1 {{Assuming 'C' is not a 'Hexagon'}} + // expected-note@-2 {{Taking false branch}} + return; + } + if (isa(C)) { // expected-note@-1 {{'C' is not a 'Triangle'}} // expected-note@-2 {{Taking false branch}} return; } + if (isa(C)) { + // expected-note@-1 {{'C' is not a 'Triangle'}} + // expected-note@-2 {{Taking false branch}} + return; + } + + if (isa(C)) { + // expected-note@-1 {{'C' is not a 'Triangle'}} + // expected-note@-2 {{Taking false branch}} + return; + } + if (isa(C)) { // expected-note@-1 {{'C' is a 'Circle'}} // expected-note@-2 {{Taking true branch}} @@ -58,9 +84,29 @@ // expected-note@-2 {{Division by zero}} // expected-warning@-3 {{Division by zero}} } + + if (isa(C)) { + // expected-note@-1 {{'C' is a 'Circle'}} + // expected-note@-2 {{Taking true branch}} + + (void)(1 / !C); + // expected-note@-1 {{'C' is non-null}} + // expected-note@-2 {{Division by zero}} + // expected-warning@-3 {{Division by zero}} + } + + if (isa(C)) { + // expected-note@-1 {{'C' is a 'Circle'}} + // expected-note@-2 {{Taking true branch}} + + (void)(1 / !C); + // expected-note@-1 {{'C' is non-null}} + // expected-note@-2 {{Division by zero}} + // expected-warning@-3 {{Division by zero}} + } } -void evalNonNullParamNonNullReturn(const Shape *S) { +/*void evalNonNullParamNonNullReturn(const Shape *S) { const auto *C = cast(S); // expected-note@-1 {{'S' is a 'Circle'}} // expected-note@-2 {{'C' initialized here}} @@ -153,3 +199,4 @@ // expected-note@-1 {{Division by zero}} // expected-warning@-2 {{Division by zero}} } +*/