PsiElementVisitor (@NotNull ProblemsHolder holder, boolean isOnTheFly) { if (!PsiUtil.isLanguageLevel9OrHigher(holder.getFile())) { return PsiElementVisitor.EMPTY_VISITOR; } return new JavaElementVisitor() { @Override public void visitMethodCallExpression(@NotNull PsiMethodCallExpression call) { if (!CLEANER_REGISTER.test(call)) return; PsiExpression[] expressions = call.getArgumentList().getExpressions(); PsiExpression trackedObject = ExpressionUtils.resolveExpression(expressions[0]); PsiExpression runnableExpression = ExpressionUtils.resolveExpression(expressions[1]); if (trackedObject == null || runnableExpression == null) return; final PsiElement highlightingElement; final String referenceName; if (trackedObject instanceof PsiThisExpression) { PsiClassType classType = tryCast(trackedObject.getType(), PsiClassType.class); if (classType == null) return; PsiClass trackedClass = classType.resolve(); if (trackedClass == null) return; PsiElement elementCapturingThis = getElementCapturingThis(runnableExpression, trackedClass); if (elementCapturingThis == null) return; highlightingElement = elementCapturingThis; referenceName = "this"; } else if (trackedObject instanceof PsiReferenceExpression) { PsiVariable variable = tryCast(((PsiReferenceExpression)trackedObject).resolve(), PsiVariable.class); if (variable == null) return; if (variable instanceof PsiField) return; if (!VariableAccessUtils.variableIsUsed(variable, runnableExpression)) return; Optional<PsiElement> referenceExpression = StreamEx.ofTree(((PsiElement)runnableExpression), el -> StreamEx.of(el.getChildren())) .findAny(el -> el instanceof PsiReferenceExpression && ((PsiReferenceExpression)el).isReferenceTo(variable)); if (referenceExpression.isEmpty()) return; String variableName = variable.getName(); if (variableName == null) return; highlightingElement = referenceExpression.get(); referenceName = variableName; } else { return; } holder.registerProblem(highlightingElement, JavaBundle.message("inspection.capturing.cleaner", referenceName)); } @Nullable private static PsiElement getElementCapturingThis(@NotNull PsiExpression runnableExpr, @NotNull PsiClass trackedClass) { if (runnableExpr instanceof PsiMethodReferenceExpression methodReference) { if (PsiMethodReferenceUtil.isStaticallyReferenced(methodReference)) return null; PsiElement qualifier = methodReference.getQualifier(); if (qualifier instanceof PsiThisExpression) { PsiClass thisClass = PsiUtil.resolveClassInType(((PsiThisExpression)qualifier).getType()); if (thisClass != trackedClass) return null; return qualifier; } return null; } if (runnableExpr instanceof PsiLambdaExpression lambda) { if (!lambda.getParameterList().isEmpty()) return null; PsiElement lambdaBody = lambda.getBody(); if (lambdaBody == null) return null; return getLambdaOrInnerClassElementCapturingThis(lambdaBody, trackedClass); } if (runnableExpr instanceof PsiNewExpression newExpression) { if (newExpression.getAnonymousClass() != null) { if (PsiUtil.isLanguageLevel18OrHigher(trackedClass)) { PsiElement elementCapturingThis = getLambdaOrInnerClassElementCapturingThis(newExpression, trackedClass); if (elementCapturingThis != null) { return elementCapturingThis; } } else { return newExpression; } } PsiJavaCodeReferenceElement classReference = newExpression.getClassReference(); if (classReference == null) return null; PsiClass aClass = tryCast(classReference.resolve(), PsiClass.class); if (aClass == null) return null; if (aClass.getContainingClass() != trackedClass) return null; if (aClass.hasModifierProperty(PsiModifier.STATIC)) return null; if (PsiUtil.isLanguageLevel18OrHigher(trackedClass) && getLambdaOrInnerClassElementCapturingThis(newExpression, trackedClass) == null) return null; return classReference; } return null; } }; }