20
20
import static com .google .common .collect .ImmutableSet .toImmutableSet ;
21
21
import static com .google .errorprone .util .ASTHelpers .getSymbol ;
22
22
import static com .google .errorprone .util .ASTHelpers .hasAnnotation ;
23
+ import static com .google .errorprone .util .ASTHelpers .isLocal ;
24
+ import static com .google .errorprone .util .ASTHelpers .isSuper ;
25
+ import static com .google .errorprone .util .ASTHelpers .methodCanBeOverridden ;
23
26
24
27
import com .google .auto .value .AutoValue ;
25
28
import com .google .common .collect .ImmutableSet ;
@@ -125,7 +128,8 @@ enum InlineValidationErrorReason {
125
128
+ " call to another varargs method" ),
126
129
EMPTY_VOID ("InlineMe cannot yet be applied to no-op void methods" ),
127
130
REUSE_OF_ARGUMENTS ("Implementations cannot use an argument more than once:" ),
128
- PARAM_NAMES_ARE_NAMED_ARGN ("Method parameter names cannot match `arg[0-9]+`." );
131
+ PARAM_NAMES_ARE_NAMED_ARGN ("Method parameter names cannot match `arg[0-9]+`." ),
132
+ NO_SUPER_CALLS ("super(...) calls cannot be inlined." );
129
133
130
134
private final @ Nullable String errorMessage ;
131
135
@@ -142,21 +146,21 @@ static boolean matchesArgN(String paramName) {
142
146
return paramName .matches ("arg[0-9]+" );
143
147
}
144
148
145
- static InlinabilityResult forMethod (MethodTree tree , VisitorState state ) {
146
- if (tree .getBody () == null ) {
149
+ static InlinabilityResult forMethod (MethodTree methodTree , VisitorState state ) {
150
+ if (methodTree .getBody () == null ) {
147
151
return fromError (InlineValidationErrorReason .NO_BODY );
148
152
}
149
153
150
- if (tree .getBody ().getStatements ().size () != 1 ) {
154
+ if (methodTree .getBody ().getStatements ().size () != 1 ) {
151
155
return fromError (InlineValidationErrorReason .NOT_EXACTLY_ONE_STATEMENT );
152
156
}
153
157
154
- MethodSymbol methSymbol = getSymbol (tree );
155
- if (methSymbol .getModifiers ().contains (Modifier .PRIVATE )) {
158
+ MethodSymbol methodSym = getSymbol (methodTree );
159
+ if (methodSym .getModifiers ().contains (Modifier .PRIVATE )) {
156
160
return fromError (InlineValidationErrorReason .API_IS_PRIVATE );
157
161
}
158
162
159
- StatementTree statement = tree .getBody ().getStatements ().get (0 );
163
+ StatementTree statement = methodTree .getBody ().getStatements ().get (0 );
160
164
161
165
if (state .getSourceForNode (statement ) == null ) {
162
166
return fromError (InlineValidationErrorReason .NO_BODY );
@@ -179,11 +183,16 @@ static InlinabilityResult forMethod(MethodTree tree, VisitorState state) {
179
183
}
180
184
}
181
185
182
- if (methSymbol .isVarArgs () && usesVarargsParamPoorly (body , methSymbol .params ().last (), state )) {
186
+ if (body instanceof MethodInvocationTree methodInvocation
187
+ && isSuper (methodInvocation .getMethodSelect ())) {
188
+ return fromError (InlineValidationErrorReason .NO_SUPER_CALLS );
189
+ }
190
+
191
+ if (methodSym .isVarArgs () && usesVarargsParamPoorly (body , methodSym .params ().last (), state )) {
183
192
return fromError (InlineValidationErrorReason .VARARGS_USED_UNSAFELY , body );
184
193
}
185
194
186
- for (VarSymbol param : methSymbol .params ()) {
195
+ for (VarSymbol param : methodSym .params ()) {
187
196
if (matchesArgN (param .name .toString ())) {
188
197
return fromError (InlineValidationErrorReason .PARAM_NAMES_ARE_NAMED_ARGN );
189
198
}
@@ -195,30 +204,30 @@ static InlinabilityResult forMethod(MethodTree tree, VisitorState state) {
195
204
return fromError (InlineValidationErrorReason .COMPLEX_STATEMENT , body );
196
205
}
197
206
198
- Symbol usedMultipleTimes = usesVariablesMultipleTimes (body , methSymbol .params (), state );
207
+ Symbol usedMultipleTimes = usesVariablesMultipleTimes (body , methodSym .params (), state );
199
208
if (usedMultipleTimes != null ) {
200
209
return fromError (
201
210
InlineValidationErrorReason .REUSE_OF_ARGUMENTS , body , usedMultipleTimes .toString ());
202
211
}
203
212
204
213
Tree privateOrDeprecatedApi =
205
- usesPrivateOrDeprecatedApis (body , state , getVisibility (methSymbol ));
214
+ usesPrivateOrDeprecatedApis (body , state , getVisibility (methodSym ));
206
215
if (privateOrDeprecatedApi != null ) {
207
216
return fromError (
208
217
InlineValidationErrorReason .CALLS_DEPRECATED_OR_PRIVATE_APIS ,
209
218
body ,
210
219
state .getSourceForNode (privateOrDeprecatedApi ));
211
220
}
212
221
213
- if (hasArgumentInPossiblyNonExecutedPosition (tree , body )) {
222
+ if (hasArgumentInPossiblyNonExecutedPosition (methodTree , body )) {
214
223
return fromError (InlineValidationErrorReason .BODY_WOULD_EVALUATE_DIFFERENTLY , body );
215
224
}
216
225
217
- if (ASTHelpers . methodCanBeOverridden (methSymbol )) {
226
+ if (methodCanBeOverridden (methodSym )) {
218
227
// TODO(glorioso): One additional edge case we can check is if the owning class can't be
219
228
// overridden due to having no publicly-accessible constructors.
220
229
return fromError (
221
- methSymbol .isDefault ()
230
+ methodSym .isDefault ()
222
231
? InlineValidationErrorReason .METHOD_CAN_BE_OVERRIDDEN_AND_CANT_BE_FIXED
223
232
: InlineValidationErrorReason .METHOD_CAN_BE_OVERRIDDEN_BUT_CAN_BE_FIXED ,
224
233
body );
@@ -234,7 +243,7 @@ private static Symbol usesVariablesMultipleTimes(
234
243
final Set <Symbol > usedVariables = new HashSet <>();
235
244
236
245
@ Override
237
- public Void visitIdentifier (IdentifierTree identifierTree , Void aVoid ) {
246
+ public Void visitIdentifier (IdentifierTree identifierTree , Void unused ) {
238
247
Symbol usedSymbol = getSymbol (identifierTree );
239
248
if (parameterVariables .contains (usedSymbol ) && !usedVariables .add (usedSymbol )) {
240
249
usesVarsTwice .set (usedSymbol );
@@ -252,7 +261,7 @@ private static boolean usesVarargsParamPoorly(
252
261
AtomicBoolean usesVarargsPoorly = new AtomicBoolean (false );
253
262
new TreePathScanner <Void , Void >() {
254
263
@ Override
255
- public Void visitIdentifier (IdentifierTree identifierTree , Void aVoid ) {
264
+ public Void visitIdentifier (IdentifierTree identifierTree , Void unused ) {
256
265
if (!getSymbol (identifierTree ).equals (varargsParam )) {
257
266
return super .visitIdentifier (identifierTree , null );
258
267
}
@@ -293,48 +302,47 @@ private static Tree usesPrivateOrDeprecatedApis(
293
302
AtomicReference <Tree > usesDeprecatedOrLessVisibleApis = new AtomicReference <>();
294
303
new TreeScanner <Void , Void >() {
295
304
@ Override
296
- public Void visitLambdaExpression (LambdaExpressionTree node , Void unused ) {
297
- // we override so we can ignore the node .getParameters()
298
- return super .scan (node .getBody (), null );
305
+ public Void visitLambdaExpression (LambdaExpressionTree lambda , Void unused ) {
306
+ // we override so we can ignore the lambda .getParameters()
307
+ return super .scan (lambda .getBody (), null );
299
308
}
300
309
301
310
@ Override
302
- public Void visitMemberSelect (MemberSelectTree memberSelectTree , Void aVoid ) {
311
+ public Void visitMemberSelect (MemberSelectTree memberSelect , Void unused ) {
303
312
// This check is necessary as the TreeScanner doesn't visit the "name" part of the
304
313
// left-hand of an assignment.
305
- if (isDeprecatedOrLessVisible (memberSelectTree , minVisibility )) {
306
- // short circuit
307
- return null ;
314
+ if (isDeprecatedOrLessVisible (memberSelect , minVisibility )) {
315
+ return null ; // short-circuit
308
316
}
309
- return super .visitMemberSelect (memberSelectTree , null );
317
+ return super .visitMemberSelect (memberSelect , null );
310
318
}
311
319
312
320
@ Override
313
- public Void visitIdentifier (IdentifierTree node , Void unused ) {
314
- if (!ASTHelpers . isLocal (getSymbol (node ))) {
315
- if (!node .getName ().contentEquals ("this" )) {
316
- if (isDeprecatedOrLessVisible (node , minVisibility )) {
321
+ public Void visitIdentifier (IdentifierTree identifierTree , Void unused ) {
322
+ if (!isLocal (getSymbol (identifierTree ))) {
323
+ if (!identifierTree .getName ().contentEquals ("this" )) {
324
+ if (isDeprecatedOrLessVisible (identifierTree , minVisibility )) {
317
325
return null ; // short-circuit
318
326
}
319
327
}
320
328
}
321
- return super .visitIdentifier (node , null );
329
+ return super .visitIdentifier (identifierTree , null );
322
330
}
323
331
324
332
@ Override
325
- public Void visitNewClass (NewClassTree newClassTree , Void aVoid ) {
333
+ public Void visitNewClass (NewClassTree newClassTree , Void unused ) {
326
334
if (isDeprecatedOrLessVisible (newClassTree , minVisibility )) {
327
- return null ;
335
+ return null ; // short-circuit
328
336
}
329
337
return super .visitNewClass (newClassTree , null );
330
338
}
331
339
332
340
@ Override
333
- public Void visitMethodInvocation (MethodInvocationTree node , Void unused ) {
334
- if (isDeprecatedOrLessVisible (node , minVisibility )) {
341
+ public Void visitMethodInvocation (MethodInvocationTree methodInvocation , Void unused ) {
342
+ if (isDeprecatedOrLessVisible (methodInvocation , minVisibility )) {
335
343
return null ; // short-circuit
336
344
}
337
- return super .visitMethodInvocation (node , null );
345
+ return super .visitMethodInvocation (methodInvocation , null );
338
346
}
339
347
340
348
private boolean isDeprecatedOrLessVisible (Tree tree , Visibility minVisibility ) {
@@ -376,43 +384,43 @@ private static Visibility getVisibility(Symbol symbol) {
376
384
}
377
385
378
386
private static boolean hasArgumentInPossiblyNonExecutedPosition (
379
- MethodTree meth , ExpressionTree statement ) {
387
+ MethodTree methodTree , ExpressionTree statement ) {
380
388
AtomicBoolean paramReferred = new AtomicBoolean (false );
381
389
ImmutableSet <VarSymbol > params =
382
- meth .getParameters ().stream ().map (ASTHelpers ::getSymbol ).collect (toImmutableSet ());
390
+ methodTree .getParameters ().stream ().map (ASTHelpers ::getSymbol ).collect (toImmutableSet ());
383
391
new TreeScanner <Void , Void >() {
384
392
Tree currentContextTree = null ;
385
393
386
394
@ Override
387
- public Void visitLambdaExpression (LambdaExpressionTree lambdaExpressionTree , Void o ) {
395
+ public Void visitLambdaExpression (LambdaExpressionTree lambda , Void unused ) {
388
396
Tree lastContext = currentContextTree ;
389
- currentContextTree = lambdaExpressionTree ;
390
- scan (lambdaExpressionTree .getBody (), null );
397
+ currentContextTree = lambda ;
398
+ scan (lambda .getBody (), null );
391
399
currentContextTree = lastContext ;
392
400
return null ;
393
401
}
394
402
395
403
@ Override
396
- public Void visitConditionalExpression (ConditionalExpressionTree ceTree , Void o ) {
397
- scan (ceTree .getCondition (), null );
404
+ public Void visitConditionalExpression (ConditionalExpressionTree conditional , Void unused ) {
405
+ scan (conditional .getCondition (), null );
398
406
// If the variables show up in the left or right side, they may conditionally not be
399
407
// executed.
400
408
Tree lastContext = currentContextTree ;
401
- currentContextTree = ceTree ;
402
- scan (ceTree .getTrueExpression (), null );
403
- scan (ceTree .getFalseExpression (), null );
409
+ currentContextTree = conditional ;
410
+ scan (conditional .getTrueExpression (), null );
411
+ scan (conditional .getFalseExpression (), null );
404
412
currentContextTree = lastContext ;
405
413
return null ;
406
414
}
407
415
408
416
@ Override
409
- public Void visitIdentifier (IdentifierTree identifierTree , Void aVoid ) {
417
+ public Void visitIdentifier (IdentifierTree identifier , Void unused ) {
410
418
// If the lambda captures method parameters, inlining the method body can change the
411
419
// timing of the evaluation of the arguments.
412
- if (currentContextTree != null && params .contains (getSymbol (identifierTree ))) {
420
+ if (currentContextTree != null && params .contains (getSymbol (identifier ))) {
413
421
paramReferred .set (true );
414
422
}
415
- return super .visitIdentifier (identifierTree , null );
423
+ return super .visitIdentifier (identifier , null );
416
424
}
417
425
}.scan (statement , null );
418
426
return paramReferred .get ();
0 commit comments