Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -1340,13 +1340,12 @@ static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI) { const auto *VR = cast(SI.Dest); - const auto *Param = cast(VR->getDecl()); + const auto *D = VR->getDecl(); OS << "Passing "; if (isa(SI.Value)) { - OS << (isObjCPointer(Param) ? "nil object reference" - : "null pointer value"); + OS << (isObjCPointer(D) ? "nil object reference" : "null pointer value"); } else if (SI.Value.isUndef()) { OS << "uninitialized value"; @@ -1361,12 +1360,29 @@ OS << "value"; } - // Printed parameter indexes are 1-based, not 0-based. - unsigned Idx = Param->getFunctionScopeIndex() + 1; - OS << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter"; - if (VR->canPrintPretty()) { - OS << " "; - VR->printPretty(OS); + if (const auto *Param = dyn_cast(VR->getDecl())) { + // Printed parameter indexes are 1-based, not 0-based. + unsigned Idx = Param->getFunctionScopeIndex() + 1; + OS << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter"; + if (VR->canPrintPretty()) { + OS << " "; + VR->printPretty(OS); + } + } else if (const auto *ImplParam = dyn_cast(D)) { + switch (ImplParam->getParameterKind()) { + case ImplicitParamDecl::ImplicitParamKind::ObjCSelf: + OS << " via implicit parameter 'self'"; + break; + case ImplicitParamDecl::ImplicitParamKind::CXXThis: + OS << " via implicit parameter 'this'"; + break; + case ImplicitParamDecl::ImplicitParamKind::ObjCCmd: + case ImplicitParamDecl::ImplicitParamKind::CXXVTT: + case ImplicitParamDecl::ImplicitParamKind::CapturedContext: + case ImplicitParamDecl::ImplicitParamKind::ThreadPrivateVar: + case ImplicitParamDecl::ImplicitParamKind::Other: + break; + }; } } Index: clang/test/Analysis/path-notes-impl-param.m =================================================================== --- /dev/null +++ clang/test/Analysis/path-notes-impl-param.m @@ -0,0 +1,31 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-output=text -verify %s + +@protocol NSObject +@end + +@interface NSObject {} +- (id)init; ++ (id)alloc; +- (id)autorelease; +@end + +@interface Foo : NSObject +@property(nonatomic) int bar; +@end + +@implementation Foo +-(int)bar { + return 0; +} +@end + +int baz() { + Foo *f = [Foo alloc]; + // expected-note@-1 {{'f' initialized here}} + // expected-note@-2 {{Method returns an instance of Foo with a +1 retain count}} + + return f.bar; + // expected-warning@-1 {{Potential leak of an object stored into 'self' [osx.cocoa.RetainCount]}} + // expected-note@-2 {{Passing value via implicit parameter 'self'}} + // expected-note@-3 {{Object leaked: object allocated and stored into 'self' is not referenced later in this execution path and has a retain count of +1}} +}