Index: include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h =================================================================== --- include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -550,13 +550,15 @@ class PathDiagnosticCallPiece : public PathDiagnosticPiece { PathDiagnosticCallPiece(const Decl *callerD, const PathDiagnosticLocation &callReturnPos) - : PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr), - NoExit(false), callReturn(callReturnPos) {} + : PathDiagnosticPiece(Call), Caller(callerD), Callee(nullptr), + NoExit(false), IsCalleeAnAutosynthesizedPropertyAccessor(false), + callReturn(callReturnPos) {} PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller) - : PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr), - NoExit(true), path(oldPath) {} - + : PathDiagnosticPiece(Call), Caller(caller), Callee(nullptr), + NoExit(true), IsCalleeAnAutosynthesizedPropertyAccessor(false), + path(oldPath) {} + const Decl *Caller; const Decl *Callee; @@ -564,6 +566,10 @@ // call exit. bool NoExit; + // Flag signifying that the callee function is an Objective-C autosynthesized + // property getter or setter. + bool IsCalleeAnAutosynthesizedPropertyAccessor; + // The custom string, which should appear after the call Return Diagnostic. // TODO: Should we allow multiple diagnostics? std::string CallStackMessage; Index: lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -326,7 +326,7 @@ // Retrieve the associated statement. const Stmt *S = TrackedNullab->getNullabilitySource(); - if (!S) { + if (!S || S->getLocStart().isInvalid()) { S = PathDiagnosticLocation::getStmt(N); } Index: lib/StaticAnalyzer/Core/PathDiagnostic.cpp =================================================================== --- lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -695,6 +695,18 @@ } const Stmt *PathDiagnosticLocation::getStmt(const ExplodedNode *N) { + // We cannot place diagnostics on autosynthesized code. + // Put them onto the call site through which we jumped into autosynthesized + // code for the first time. + const LocationContext *LC = N->getLocationContext(); + if (LC->getAnalysisDeclContext()->isBodyAutosynthesized()) { + const LocationContext *ParentLC = LC->getParent(); + while (ParentLC->getAnalysisDeclContext()->isBodyAutosynthesized()) { + LC = ParentLC; + ParentLC = LC->getParent(); + } + return LC->getCurrentStackFrame()->getCallSite(); + } ProgramPoint P = N->getLocation(); if (Optional SP = P.getAs()) return SP->getStmt(); @@ -912,6 +924,12 @@ callEnterWithin = PathDiagnosticLocation::createBegin(Callee, SM); callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM); + + // Otherwise IsCalleeAnAutosynthesizedPropertyAccessor defaults to false. + if (const ObjCMethodDecl *MD = dyn_cast(Callee)) + IsCalleeAnAutosynthesizedPropertyAccessor = ( + MD->isPropertyAccessor() && + CalleeCtx->getAnalysisDeclContext()->isBodyAutosynthesized()); } static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D, @@ -986,7 +1004,7 @@ std::shared_ptr PathDiagnosticCallPiece::getCallEnterEvent() const { - if (!Callee) + if (!Callee || IsCalleeAnAutosynthesizedPropertyAccessor) return nullptr; SmallString<256> buf; @@ -1020,7 +1038,7 @@ std::shared_ptr PathDiagnosticCallPiece::getCallExitEvent() const { - if (NoExit) + if (NoExit || IsCalleeAnAutosynthesizedPropertyAccessor) return nullptr; SmallString<256> buf; Index: test/Analysis/nullability-notes.m =================================================================== --- /dev/null +++ test/Analysis/nullability-notes.m @@ -0,0 +1,18 @@ +// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -analyzer-output=text -verify %s + +#include "Inputs/system-header-simulator-for-nullability.h" + +void takesNonnull(NSObject *_Nonnull y); + +@interface ClassWithProperties: NSObject +@property(copy, nullable) NSObject *x; +-(void) method; +@end; +@implementation ClassWithProperties +-(void) method { + // no-crash + NSObject *x = self.x; // expected-note{{Nullability 'nullable' is inferred}} + takesNonnull(x); // expected-warning{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}} + // expected-note@-1{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}} +} +@end