private static void checkCodeBlock( final PsiCodeBlock body, final Set<PsiField> candidates, Set<PsiField> usedFields) { try { final ControlFlow controlFlow = ControlFlowFactory.getInstance(body.getProject()) .getControlFlow(body, AllVariablesControlFlowPolicy.getInstance()); final List<PsiVariable> usedVars = ControlFlowUtil.getUsedVariables(controlFlow, 0, controlFlow.getSize()); for (PsiVariable usedVariable : usedVars) { if (usedVariable instanceof PsiField) { final PsiField usedField = (PsiField) usedVariable; if (!usedFields.add(usedField)) { candidates.remove(usedField); // used in more than one code block } } } final List<PsiReferenceExpression> readBeforeWrites = ControlFlowUtil.getReadBeforeWrite(controlFlow); for (final PsiReferenceExpression readBeforeWrite : readBeforeWrites) { final PsiElement resolved = readBeforeWrite.resolve(); if (resolved instanceof PsiField) { final PsiField field = (PsiField) resolved; PsiElement parent = body.getParent(); if (!(parent instanceof PsiMethod) || !((PsiMethod) parent).isConstructor() || field.getInitializer() == null || field.hasModifierProperty(PsiModifier.STATIC)) { candidates.remove(field); } } } } catch (AnalysisCanceledException e) { candidates.clear(); } }
private static boolean isCollectCall(PsiStatement body, final PsiParameter parameter) { PsiIfStatement ifStatement = extractIfStatement(body); final PsiMethodCallExpression methodCallExpression = extractAddCall(body, ifStatement); if (methodCallExpression != null) { final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); final PsiExpression qualifierExpression = methodExpression.getQualifierExpression(); PsiClass qualifierClass = null; if (qualifierExpression instanceof PsiReferenceExpression) { if (ReferencesSearch.search(parameter, new LocalSearchScope(qualifierExpression)) .findFirst() != null) { return false; } final PsiElement resolve = ((PsiReferenceExpression) qualifierExpression).resolve(); if (resolve instanceof PsiVariable) { if (ReferencesSearch.search( resolve, new LocalSearchScope(methodCallExpression.getArgumentList())) .findFirst() != null) { return false; } } qualifierClass = PsiUtil.resolveClassInType(qualifierExpression.getType()); } else if (qualifierExpression == null) { final PsiClass enclosingClass = PsiTreeUtil.getParentOfType(body, PsiClass.class); if (PsiUtil.getEnclosingStaticElement(body, enclosingClass) == null) { qualifierClass = enclosingClass; } } if (qualifierClass != null && InheritanceUtil.isInheritor( qualifierClass, false, CommonClassNames.JAVA_UTIL_COLLECTION)) { while (ifStatement != null && PsiTreeUtil.isAncestor(body, ifStatement, false)) { final PsiExpression condition = ifStatement.getCondition(); if (condition != null && isConditionDependsOnUpdatedCollections(condition, qualifierExpression)) return false; ifStatement = PsiTreeUtil.getParentOfType(ifStatement, PsiIfStatement.class); } final PsiElement resolve = methodExpression.resolve(); if (resolve instanceof PsiMethod && "add".equals(((PsiMethod) resolve).getName()) && ((PsiMethod) resolve).getParameterList().getParametersCount() == 1) { final PsiExpression[] args = methodCallExpression.getArgumentList().getExpressions(); if (args.length == 1) { if (args[0] instanceof PsiCallExpression) { final PsiMethod method = ((PsiCallExpression) args[0]).resolveMethod(); return method != null && !method.hasTypeParameters() && !isThrowsCompatible(method); } return true; } } } } return false; }
public static boolean isEffectivelyFinal( @NotNull PsiVariable variable, @NotNull PsiElement scope, @Nullable PsiJavaCodeReferenceElement context) { boolean effectivelyFinal; if (variable instanceof PsiParameter) { effectivelyFinal = notAccessedForWriting( variable, new LocalSearchScope(((PsiParameter) variable).getDeclarationScope())); } else { final ControlFlow controlFlow; try { PsiElement codeBlock = PsiUtil.getVariableCodeBlock(variable, context); if (codeBlock == null) return true; controlFlow = getControlFlow(codeBlock); } catch (AnalysisCanceledException e) { return true; } final List<PsiReferenceExpression> readBeforeWriteLocals = ControlFlowUtil.getReadBeforeWriteLocals(controlFlow); for (PsiReferenceExpression expression : readBeforeWriteLocals) { if (expression.resolve() == variable) { return PsiUtil.isAccessedForReading(expression); } } final Collection<ControlFlowUtil.VariableInfo> initializedTwice = ControlFlowUtil.getInitializedTwice(controlFlow); effectivelyFinal = !initializedTwice.contains(new ControlFlowUtil.VariableInfo(variable, null)); if (effectivelyFinal) { effectivelyFinal = notAccessedForWriting(variable, new LocalSearchScope(scope)); } } return effectivelyFinal; }
@Nullable static HighlightInfo checkCannotWriteToFinal( @NotNull PsiExpression expression, @NotNull PsiFile containingFile) { PsiReferenceExpression reference = null; boolean readBeforeWrite = false; if (expression instanceof PsiAssignmentExpression) { final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression) expression; final PsiExpression left = PsiUtil.skipParenthesizedExprDown(assignmentExpression.getLExpression()); if (left instanceof PsiReferenceExpression) { reference = (PsiReferenceExpression) left; } readBeforeWrite = assignmentExpression.getOperationTokenType() != JavaTokenType.EQ; } else if (expression instanceof PsiPostfixExpression) { final PsiExpression operand = PsiUtil.skipParenthesizedExprDown(((PsiPostfixExpression) expression).getOperand()); final IElementType sign = ((PsiPostfixExpression) expression).getOperationTokenType(); if (operand instanceof PsiReferenceExpression && (sign == JavaTokenType.PLUSPLUS || sign == JavaTokenType.MINUSMINUS)) { reference = (PsiReferenceExpression) operand; } readBeforeWrite = true; } else if (expression instanceof PsiPrefixExpression) { final PsiExpression operand = PsiUtil.skipParenthesizedExprDown(((PsiPrefixExpression) expression).getOperand()); final IElementType sign = ((PsiPrefixExpression) expression).getOperationTokenType(); if (operand instanceof PsiReferenceExpression && (sign == JavaTokenType.PLUSPLUS || sign == JavaTokenType.MINUSMINUS)) { reference = (PsiReferenceExpression) operand; } readBeforeWrite = true; } final PsiElement resolved = reference == null ? null : reference.resolve(); PsiVariable variable = resolved instanceof PsiVariable ? (PsiVariable) resolved : null; if (variable == null || !variable.hasModifierProperty(PsiModifier.FINAL)) return null; final boolean canWrite = canWriteToFinal(variable, expression, reference, containingFile) && checkWriteToFinalInsideLambda(variable, reference) == null; if (readBeforeWrite || !canWrite) { final String name = variable.getName(); String description = canWrite ? JavaErrorMessages.message("variable.not.initialized", name) : JavaErrorMessages.message("assignment.to.final.variable", name); final HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) .range(reference.getTextRange()) .descriptionAndTooltip(description) .create(); final PsiElement innerClass = getInnerClassVariableReferencedFrom(variable, expression); if (innerClass == null || variable instanceof PsiField) { QuickFixAction.registerQuickFixAction( highlightInfo, QUICK_FIX_FACTORY.createModifierListFix(variable, PsiModifier.FINAL, false, false)); } else { QuickFixAction.registerQuickFixAction( highlightInfo, QUICK_FIX_FACTORY.createVariableAccessFromInnerClassFix(variable, innerClass)); } return highlightInfo; } return null; }