diff options
| author | Devin Coughlin <dcoughlin@apple.com> | 2016-04-13 17:59:24 +0000 |
|---|---|---|
| committer | Devin Coughlin <dcoughlin@apple.com> | 2016-04-13 17:59:24 +0000 |
| commit | 4ac12425ba3904ba5796b183f635af5c6a25f741 (patch) | |
| tree | 86af2a9c23ba6f00f319450c0323008c8af64aa4 /clang/lib/StaticAnalyzer/Checkers | |
| parent | 6662d6ad2add5329a462bf70381646e5e7ec39bf (diff) | |
| download | bcm5719-llvm-4ac12425ba3904ba5796b183f635af5c6a25f741.tar.gz bcm5719-llvm-4ac12425ba3904ba5796b183f635af5c6a25f741.zip | |
[analyzer] Nullability: Suppress diagnostic on bind with cast.
Update the nullability checker to allow an explicit cast to nonnull to
suppress a warning on an assignment of nil to a nonnull:
id _Nonnull x = (id _Nonnull)nil; // no-warning
This suppression as already possible for diagnostics on returns and
function/method arguments.
rdar://problem/25381178
llvm-svn: 266219
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp | 34 |
1 files changed, 28 insertions, 6 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp index 0941b5240e9..d7ec6b10c6f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -1103,26 +1103,48 @@ void NullabilityChecker::checkBind(SVal L, SVal V, const Stmt *S, ValNullability = getNullabilityAnnotation(Sym->getType()); Nullability LocNullability = getNullabilityAnnotation(LocType); + + // If the type of the RHS expression is nonnull, don't warn. This + // enables explicit suppression with a cast to nonnull. + Nullability ValueExprTypeLevelNullability = Nullability::Unspecified; + const Expr *ValueExpr = matchValueExprForBind(S); + if (ValueExpr) { + ValueExprTypeLevelNullability = + getNullabilityAnnotation(lookThroughImplicitCasts(ValueExpr)->getType()); + } + + bool NullAssignedToNonNull = (LocNullability == Nullability::Nonnull && + RhsNullness == NullConstraint::IsNull); if (Filter.CheckNullPassedToNonnull && - RhsNullness == NullConstraint::IsNull && + NullAssignedToNonNull && ValNullability != Nullability::Nonnull && - LocNullability == Nullability::Nonnull && + ValueExprTypeLevelNullability != Nullability::Nonnull && !isARCNilInitializedLocal(C, S)) { static CheckerProgramPointTag Tag(this, "NullPassedToNonnull"); ExplodedNode *N = C.generateErrorNode(State, &Tag); if (!N) return; - const Stmt *ValueExpr = matchValueExprForBind(S); - if (!ValueExpr) - ValueExpr = S; + + const Stmt *ValueStmt = S; + if (ValueExpr) + ValueStmt = ValueExpr; reportBugIfInvariantHolds("Null is assigned to a pointer which is " "expected to have non-null value", ErrorKind::NilAssignedToNonnull, N, nullptr, C, - ValueExpr); + ValueStmt); + return; + } + + // If null was returned from a non-null function, mark the nullability + // invariant as violated even if the diagnostic was suppressed. + if (NullAssignedToNonNull) { + State = State->set<InvariantViolated>(true); + C.addTransition(State); return; } + // Intentionally missing case: '0' is bound to a reference. It is handled by // the DereferenceChecker. |

