Skip to content

Commit 7c0ab86

Browse files
committed
[analyzer] Don't add arrow to the inlined function's decl when it has no body.
In plist output mode with alternate path diagnostics, when entering a function, we draw an arrow from the caller to the beginning of the callee's declaration. Upon exiting, however, we draw the arrow from the last statement in the callee function. The former makes little sense when the declaration is not a definition, i.e. has no body, which may happen in case the body is coming from a body farm, eg. Objective-C autosynthesized property accessor. Differential Revision: https://reviews.llvm.org/D33671 llvm-svn: 304713
1 parent 0091cc3 commit 7c0ab86

File tree

2 files changed

+196
-4
lines changed

2 files changed

+196
-4
lines changed

clang/lib/StaticAnalyzer/Core/BugReporter.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,9 +1671,15 @@ static bool GenerateAlternateExtensivePathDiagnostic(
16711671
// Add an edge to the start of the function.
16721672
const StackFrameContext *CalleeLC = CE->getCalleeContext();
16731673
const Decl *D = CalleeLC->getDecl();
1674-
addEdgeToPath(PD.getActivePath(), PrevLoc,
1675-
PathDiagnosticLocation::createBegin(D, SM),
1676-
CalleeLC);
1674+
// Add the edge only when the callee has body. We jump to the beginning
1675+
// of the *declaration*, however we expect it to be followed by the
1676+
// body. This isn't the case for autosynthesized property accessors in
1677+
// Objective-C. No need for a similar extra check for CallExit points
1678+
// because the exit edge comes from a statement (i.e. return),
1679+
// not from declaration.
1680+
if (D->hasBody())
1681+
addEdgeToPath(PD.getActivePath(), PrevLoc,
1682+
PathDiagnosticLocation::createBegin(D, SM), CalleeLC);
16771683

16781684
// Did we visit an entire call?
16791685
bool VisitedEntireCall = PD.isWithinCall();

clang/test/Analysis/nullability-notes.m

Lines changed: 187 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -analyzer-output=text -verify %s
2+
// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -analyzer-output=plist -analyzer-config path-diagnostics-alternate=true -o %t.plist %s
3+
// RUN: FileCheck --input-file=%t.plist %s
24

35
#include "Inputs/system-header-simulator-for-nullability.h"
46

57
void takesNonnull(NSObject *_Nonnull y);
68

79
@interface ClassWithProperties: NSObject
8-
@property(copy, nullable) NSObject *x;
10+
@property(copy, nullable) NSObject *x; // plist check ensures no control flow piece from here to 'self.x'.
911
-(void) method;
1012
@end;
1113
@implementation ClassWithProperties
@@ -16,3 +18,187 @@ -(void) method {
1618
// expected-note@-1{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
1719
}
1820
@end
21+
22+
// CHECK: <key>diagnostics</key>
23+
// CHECK-NEXT: <array>
24+
// CHECK-NEXT: <dict>
25+
// CHECK-NEXT: <key>path</key>
26+
// CHECK-NEXT: <array>
27+
// CHECK-NEXT: <dict>
28+
// CHECK-NEXT: <key>kind</key><string>control</string>
29+
// CHECK-NEXT: <key>edges</key>
30+
// CHECK-NEXT: <array>
31+
// CHECK-NEXT: <dict>
32+
// CHECK-NEXT: <key>start</key>
33+
// CHECK-NEXT: <array>
34+
// CHECK-NEXT: <dict>
35+
// CHECK-NEXT: <key>line</key><integer>16</integer>
36+
// CHECK-NEXT: <key>col</key><integer>3</integer>
37+
// CHECK-NEXT: <key>file</key><integer>0</integer>
38+
// CHECK-NEXT: </dict>
39+
// CHECK-NEXT: <dict>
40+
// CHECK-NEXT: <key>line</key><integer>16</integer>
41+
// CHECK-NEXT: <key>col</key><integer>10</integer>
42+
// CHECK-NEXT: <key>file</key><integer>0</integer>
43+
// CHECK-NEXT: </dict>
44+
// CHECK-NEXT: </array>
45+
// CHECK-NEXT: <key>end</key>
46+
// CHECK-NEXT: <array>
47+
// CHECK-NEXT: <dict>
48+
// CHECK-NEXT: <key>line</key><integer>16</integer>
49+
// CHECK-NEXT: <key>col</key><integer>22</integer>
50+
// CHECK-NEXT: <key>file</key><integer>0</integer>
51+
// CHECK-NEXT: </dict>
52+
// CHECK-NEXT: <dict>
53+
// CHECK-NEXT: <key>line</key><integer>16</integer>
54+
// CHECK-NEXT: <key>col</key><integer>22</integer>
55+
// CHECK-NEXT: <key>file</key><integer>0</integer>
56+
// CHECK-NEXT: </dict>
57+
// CHECK-NEXT: </array>
58+
// CHECK-NEXT: </dict>
59+
// CHECK-NEXT: </array>
60+
// CHECK-NEXT: </dict>
61+
// CHECK-NEXT: <dict>
62+
// CHECK-NEXT: <key>kind</key><string>event</string>
63+
// CHECK-NEXT: <key>location</key>
64+
// CHECK-NEXT: <dict>
65+
// CHECK-NEXT: <key>line</key><integer>16</integer>
66+
// CHECK-NEXT: <key>col</key><integer>22</integer>
67+
// CHECK-NEXT: <key>file</key><integer>0</integer>
68+
// CHECK-NEXT: </dict>
69+
// CHECK-NEXT: <key>ranges</key>
70+
// CHECK-NEXT: <array>
71+
// CHECK-NEXT: <array>
72+
// CHECK-NEXT: <dict>
73+
// CHECK-NEXT: <key>line</key><integer>16</integer>
74+
// CHECK-NEXT: <key>col</key><integer>22</integer>
75+
// CHECK-NEXT: <key>file</key><integer>0</integer>
76+
// CHECK-NEXT: </dict>
77+
// CHECK-NEXT: <dict>
78+
// CHECK-NEXT: <key>line</key><integer>16</integer>
79+
// CHECK-NEXT: <key>col</key><integer>22</integer>
80+
// CHECK-NEXT: <key>file</key><integer>0</integer>
81+
// CHECK-NEXT: </dict>
82+
// CHECK-NEXT: </array>
83+
// CHECK-NEXT: </array>
84+
// CHECK-NEXT: <key>depth</key><integer>1</integer>
85+
// CHECK-NEXT: <key>extended_message</key>
86+
// CHECK-NEXT: <string>Nullability &apos;nullable&apos; is inferred</string>
87+
// CHECK-NEXT: <key>message</key>
88+
// CHECK-NEXT: <string>Nullability &apos;nullable&apos; is inferred</string>
89+
// CHECK-NEXT: </dict>
90+
// CHECK-NEXT: <dict>
91+
// CHECK-NEXT: <key>kind</key><string>control</string>
92+
// CHECK-NEXT: <key>edges</key>
93+
// CHECK-NEXT: <array>
94+
// CHECK-NEXT: <dict>
95+
// CHECK-NEXT: <key>start</key>
96+
// CHECK-NEXT: <array>
97+
// CHECK-NEXT: <dict>
98+
// CHECK-NEXT: <key>line</key><integer>16</integer>
99+
// CHECK-NEXT: <key>col</key><integer>22</integer>
100+
// CHECK-NEXT: <key>file</key><integer>0</integer>
101+
// CHECK-NEXT: </dict>
102+
// CHECK-NEXT: <dict>
103+
// CHECK-NEXT: <key>line</key><integer>16</integer>
104+
// CHECK-NEXT: <key>col</key><integer>22</integer>
105+
// CHECK-NEXT: <key>file</key><integer>0</integer>
106+
// CHECK-NEXT: </dict>
107+
// CHECK-NEXT: </array>
108+
// CHECK-NEXT: <key>end</key>
109+
// CHECK-NEXT: <array>
110+
// CHECK-NEXT: <dict>
111+
// CHECK-NEXT: <key>line</key><integer>16</integer>
112+
// CHECK-NEXT: <key>col</key><integer>3</integer>
113+
// CHECK-NEXT: <key>file</key><integer>0</integer>
114+
// CHECK-NEXT: </dict>
115+
// CHECK-NEXT: <dict>
116+
// CHECK-NEXT: <key>line</key><integer>16</integer>
117+
// CHECK-NEXT: <key>col</key><integer>10</integer>
118+
// CHECK-NEXT: <key>file</key><integer>0</integer>
119+
// CHECK-NEXT: </dict>
120+
// CHECK-NEXT: </array>
121+
// CHECK-NEXT: </dict>
122+
// CHECK-NEXT: </array>
123+
// CHECK-NEXT: </dict>
124+
// CHECK-NEXT: <dict>
125+
// CHECK-NEXT: <key>kind</key><string>control</string>
126+
// CHECK-NEXT: <key>edges</key>
127+
// CHECK-NEXT: <array>
128+
// CHECK-NEXT: <dict>
129+
// CHECK-NEXT: <key>start</key>
130+
// CHECK-NEXT: <array>
131+
// CHECK-NEXT: <dict>
132+
// CHECK-NEXT: <key>line</key><integer>16</integer>
133+
// CHECK-NEXT: <key>col</key><integer>3</integer>
134+
// CHECK-NEXT: <key>file</key><integer>0</integer>
135+
// CHECK-NEXT: </dict>
136+
// CHECK-NEXT: <dict>
137+
// CHECK-NEXT: <key>line</key><integer>16</integer>
138+
// CHECK-NEXT: <key>col</key><integer>10</integer>
139+
// CHECK-NEXT: <key>file</key><integer>0</integer>
140+
// CHECK-NEXT: </dict>
141+
// CHECK-NEXT: </array>
142+
// CHECK-NEXT: <key>end</key>
143+
// CHECK-NEXT: <array>
144+
// CHECK-NEXT: <dict>
145+
// CHECK-NEXT: <key>line</key><integer>17</integer>
146+
// CHECK-NEXT: <key>col</key><integer>3</integer>
147+
// CHECK-NEXT: <key>file</key><integer>0</integer>
148+
// CHECK-NEXT: </dict>
149+
// CHECK-NEXT: <dict>
150+
// CHECK-NEXT: <key>line</key><integer>17</integer>
151+
// CHECK-NEXT: <key>col</key><integer>14</integer>
152+
// CHECK-NEXT: <key>file</key><integer>0</integer>
153+
// CHECK-NEXT: </dict>
154+
// CHECK-NEXT: </array>
155+
// CHECK-NEXT: </dict>
156+
// CHECK-NEXT: </array>
157+
// CHECK-NEXT: </dict>
158+
// CHECK-NEXT: <dict>
159+
// CHECK-NEXT: <key>kind</key><string>event</string>
160+
// CHECK-NEXT: <key>location</key>
161+
// CHECK-NEXT: <dict>
162+
// CHECK-NEXT: <key>line</key><integer>17</integer>
163+
// CHECK-NEXT: <key>col</key><integer>3</integer>
164+
// CHECK-NEXT: <key>file</key><integer>0</integer>
165+
// CHECK-NEXT: </dict>
166+
// CHECK-NEXT: <key>ranges</key>
167+
// CHECK-NEXT: <array>
168+
// CHECK-NEXT: <array>
169+
// CHECK-NEXT: <dict>
170+
// CHECK-NEXT: <key>line</key><integer>17</integer>
171+
// CHECK-NEXT: <key>col</key><integer>16</integer>
172+
// CHECK-NEXT: <key>file</key><integer>0</integer>
173+
// CHECK-NEXT: </dict>
174+
// CHECK-NEXT: <dict>
175+
// CHECK-NEXT: <key>line</key><integer>17</integer>
176+
// CHECK-NEXT: <key>col</key><integer>16</integer>
177+
// CHECK-NEXT: <key>file</key><integer>0</integer>
178+
// CHECK-NEXT: </dict>
179+
// CHECK-NEXT: </array>
180+
// CHECK-NEXT: </array>
181+
// CHECK-NEXT: <key>depth</key><integer>0</integer>
182+
// CHECK-NEXT: <key>extended_message</key>
183+
// CHECK-NEXT: <string>Nullable pointer is passed to a callee that requires a non-null 1st parameter</string>
184+
// CHECK-NEXT: <key>message</key>
185+
// CHECK-NEXT: <string>Nullable pointer is passed to a callee that requires a non-null 1st parameter</string>
186+
// CHECK-NEXT: </dict>
187+
// CHECK-NEXT: </array>
188+
// CHECK-NEXT: <key>description</key><string>Nullable pointer is passed to a callee that requires a non-null 1st parameter</string>
189+
// CHECK-NEXT: <key>category</key><string>Memory error</string>
190+
// CHECK-NEXT: <key>type</key><string>Nullability</string>
191+
// CHECK-NEXT: <key>check_name</key><string>nullability.NullPassedToNonnull</string>
192+
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
193+
// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>b6bc8126de8e6eb3375483a656fe858d</string>
194+
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
195+
// CHECK-NEXT: <key>issue_context</key><string>method</string>
196+
// CHECK-NEXT: <key>issue_hash_function_offset</key><string>3</string>
197+
// CHECK-NEXT: <key>location</key>
198+
// CHECK-NEXT: <dict>
199+
// CHECK-NEXT: <key>line</key><integer>17</integer>
200+
// CHECK-NEXT: <key>col</key><integer>3</integer>
201+
// CHECK-NEXT: <key>file</key><integer>0</integer>
202+
// CHECK-NEXT: </dict>
203+
// CHECK-NEXT: </dict>
204+
// CHECK-NEXT: </array>

0 commit comments

Comments
 (0)