blob: a5932ffc0ec28ed87f5df3aa39693bedde152783 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ig.psiutils;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Implementation of Java Language Specification, Chapter 16. Definite Assignment
* with some changes to match javac behavior where it does not match the specification.
* @author Bas Leijdekkers
*/
public final class DefiniteAssignmentUtil {
public static void checkVariable(PsiVariable variable, DefiniteAssignment definiteAssignment) {
if (variable instanceof PsiField) {
final PsiField field = (PsiField)variable;
checkField(field, definiteAssignment);
}
}
private static void checkField(PsiField field, DefiniteAssignment definiteAssignment) {
if (field.getInitializer() != null) {
definiteAssignment.set(true, false);
}
final PsiClass aClass = field.getContainingClass();
if (aClass == null) {
return;
}
final PsiElement[] children = aClass.getChildren();
if (field.hasModifierProperty(PsiModifier.STATIC)) {
for (PsiElement child : children) {
if (child instanceof PsiField) {
final PsiField otherField = (PsiField)child;
if (!otherField.hasModifierProperty(PsiModifier.STATIC)) {
continue;
}
checkExpression(otherField.getInitializer(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
}
else if (child instanceof PsiClassInitializer) {
final PsiClassInitializer classInitializer = (PsiClassInitializer)child;
if (!classInitializer.hasModifierProperty(PsiModifier.STATIC)) {
continue;
}
checkCodeBlock(classInitializer.getBody(), definiteAssignment);
}
}
}
else {
for (PsiElement child : children) {
if (child instanceof PsiField) {
final PsiField otherField = (PsiField)child;
if (otherField.hasModifierProperty(PsiModifier.STATIC)) {
continue;
}
checkExpression(otherField.getInitializer(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
}
else if (child instanceof PsiClassInitializer) {
final PsiClassInitializer classInitializer = (PsiClassInitializer)child;
if (classInitializer.hasModifierProperty(PsiModifier.STATIC)) {
continue;
}
checkCodeBlock(classInitializer.getBody(), definiteAssignment);
}
if (definiteAssignment.stop()) return;
}
final PsiMethod[] constructors = aClass.getConstructors();
if (constructors.length != 0) { // missing from spec?
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
boolean resultDa = true;
boolean resultDu = true;
for (PsiMethod constructor : constructors) {
checkConstructor(constructor, definiteAssignment);
resultDa &= definiteAssignment.isDefinitelyAssigned();
resultDu &= definiteAssignment.isDefinitelyUnassigned();
if (definiteAssignment.stop()) return;
definiteAssignment.set(da, du);
}
definiteAssignment.set(resultDa, resultDu);
}
}
}
private static boolean isAlternateConstructorInvocation(PsiStatement statement) {
return isConstructorInvocation(statement, PsiKeyword.THIS);
}
private static boolean isSuperClassConstructorInvocation(PsiStatement statement) {
return isConstructorInvocation(statement, PsiKeyword.SUPER);
}
private static boolean isConstructorInvocation(PsiStatement statement, @NotNull String keyword) {
if (!(statement instanceof PsiExpressionStatement)) {
return false;
}
final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)statement;
final PsiExpression expression = expressionStatement.getExpression();
if (!(expression instanceof PsiMethodCallExpression)) {
return false;
}
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
return keyword.equals(methodExpression.getReferenceName());
}
private static void checkAnonymousClass(PsiAnonymousClass anonymousClass, DefiniteAssignment definiteAssignment) {
for (PsiField field : anonymousClass.getFields()) {
checkExpression(field.getInitializer(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
}
final PsiClassInitializer[] initializers = anonymousClass.getInitializers();
for (PsiClassInitializer initializer : initializers) {
checkCodeBlock(initializer.getBody(), definiteAssignment);
}
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
for (PsiMethod method : anonymousClass.getMethods()) {
definiteAssignment.set(true, false);
checkCodeBlock(method.getBody(), definiteAssignment);
}
definiteAssignment.set(da, du);
}
private static void checkClass(PsiClass aClass, DefiniteAssignment definiteAssignment) {
for (PsiField field : aClass.getFields()) {
checkExpression(field.getInitializer(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
}
for (PsiClassInitializer initializer : aClass.getInitializers()) {
checkCodeBlock(initializer.getBody(), definiteAssignment);
}
for (PsiMethod method : aClass.getMethods()) {
checkCodeBlock(method.getBody(), definiteAssignment);
}
for (PsiClass innerClass : aClass.getInnerClasses()) {
checkClass(innerClass, definiteAssignment);
}
}
private static void checkConstructor(PsiMethod constructor, DefiniteAssignment definiteAssignment) {
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
definiteAssignment.set(false, true);
final PsiCodeBlock body = constructor.getBody();
if (body == null) {
return;
}
final PsiStatement[] statements = body.getStatements();
boolean superCalled = false;
for (int i = 0; i < statements.length; i++) {
final PsiStatement statement = statements[i];
if (i == 0) {
if (isAlternateConstructorInvocation(statement)) {
checkStatement(statement, definiteAssignment);
definiteAssignment.set(true, false);
superCalled = true;
continue;
}
else if (isSuperClassConstructorInvocation(statement)) {
checkStatement(statement, definiteAssignment);
definiteAssignment.set(da, du);
superCalled = true;
continue;
}
}
if (!superCalled) {
// implicit super call
definiteAssignment.set(da, du);
superCalled = true;
}
checkStatement(statement,definiteAssignment);
}
if (!superCalled) {
// constructor has no statements
definiteAssignment.set(da, du);
}
definiteAssignment.andDefiniteAssignmentBeforeReturn(constructor); // missing from spec?
}
private static void checkCodeBlock(@Nullable PsiCodeBlock codeBlock, DefiniteAssignment definiteAssignment) {
if (codeBlock == null) {
return;
}
for (PsiStatement statement : codeBlock.getStatements()) {
checkStatement(statement, definiteAssignment);
}
}
private static void checkLocalVariable(PsiLocalVariable localVariable, DefiniteAssignment definiteAssignment) {
final PsiExpression initializer = localVariable.getInitializer();
if (initializer != null && definiteAssignment.getVariable() == localVariable) {
definiteAssignment.set(true, false);
}
checkExpression(initializer, definiteAssignment, BooleanExpressionValue.UNDEFINED);
}
private static void checkStatement(@Nullable PsiStatement statement, DefiniteAssignment definiteAssignment) {
if (statement == null || definiteAssignment.stop() || statement instanceof PsiEmptyStatement) {
return;
}
if (statement instanceof PsiAssertStatement) {
final PsiAssertStatement assertStatement = (PsiAssertStatement)statement;
checkAssertStatement(assertStatement, definiteAssignment);
}
else if (statement instanceof PsiBlockStatement) {
final PsiBlockStatement blockStatement = (PsiBlockStatement)statement;
checkCodeBlock(blockStatement.getCodeBlock(), definiteAssignment);
}
else if (statement instanceof PsiBreakStatement) {
final PsiBreakStatement breakStatement = (PsiBreakStatement)statement;
checkBreakStatement(breakStatement, definiteAssignment);
}
else if (statement instanceof PsiContinueStatement) {
final PsiContinueStatement continueStatement = (PsiContinueStatement)statement;
checkContinueStatement(continueStatement, definiteAssignment);
}
else if (statement instanceof PsiDeclarationStatement) {
final PsiDeclarationStatement declarationStatement = (PsiDeclarationStatement)statement;
checkDeclarationStatement(declarationStatement, definiteAssignment);
}
else if (statement instanceof PsiDoWhileStatement) {
final PsiDoWhileStatement doWhileStatement = (PsiDoWhileStatement)statement;
checkDoWhileStatement(doWhileStatement, definiteAssignment);
}
else if (statement instanceof PsiExpressionStatement) {
final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)statement;
checkExpression(expressionStatement.getExpression(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
}
else if (statement instanceof PsiExpressionListStatement) {
final PsiExpressionListStatement expressionListStatement = (PsiExpressionListStatement)statement;
checkExpressionListStatement(expressionListStatement, definiteAssignment);
}
else if (statement instanceof PsiForeachStatement) {
final PsiForeachStatement foreachStatement = (PsiForeachStatement)statement;
checkForeachStatement(foreachStatement, definiteAssignment);
}
else if (statement instanceof PsiForStatement) {
final PsiForStatement forStatement = (PsiForStatement)statement;
checkForStatement(forStatement, definiteAssignment);
}
else if (statement instanceof PsiIfStatement) {
final PsiIfStatement ifStatement = (PsiIfStatement)statement;
checkIfStatement(ifStatement, definiteAssignment);
}
else if (statement instanceof PsiLabeledStatement) {
final PsiLabeledStatement labeledStatement = (PsiLabeledStatement)statement;
checkLabeledStatement(labeledStatement, definiteAssignment);
}
else if (statement instanceof PsiReturnStatement) {
final PsiReturnStatement returnStatement = (PsiReturnStatement)statement;
checkReturnStatement(returnStatement, definiteAssignment);
}
else if (statement instanceof PsiSwitchStatement) {
final PsiSwitchStatement switchStatement = (PsiSwitchStatement)statement;
checkSwitchStatement(switchStatement, definiteAssignment);
}
else if (statement instanceof PsiSynchronizedStatement) {
final PsiSynchronizedStatement synchronizedStatement = (PsiSynchronizedStatement)statement;
checkSynchronizedStatement(synchronizedStatement, definiteAssignment);
}
else if (statement instanceof PsiThrowStatement) {
final PsiThrowStatement throwStatement = (PsiThrowStatement)statement;
checkThrowStatement(throwStatement, definiteAssignment);
}
else if (statement instanceof PsiTryStatement) {
final PsiTryStatement tryStatement = (PsiTryStatement)statement;
checkTryStatement(tryStatement, definiteAssignment);
}
else if (statement instanceof PsiWhileStatement) {
final PsiWhileStatement whileStatement = (PsiWhileStatement)statement;
checkWhileStatement(whileStatement, definiteAssignment);
}
}
private static void checkAssertStatement(PsiAssertStatement assertStatement, DefiniteAssignment definiteAssignment) {
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
final PsiExpression condition = assertStatement.getAssertCondition();
checkExpression(condition, definiteAssignment, BooleanExpressionValue.WHEN_TRUE);
final boolean resultDu = du && definiteAssignment.isDefinitelyUnassigned();
definiteAssignment.set(da, du);
checkExpression(condition, definiteAssignment, BooleanExpressionValue.WHEN_FALSE);
checkExpression(assertStatement.getAssertDescription(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
definiteAssignment.set(da, resultDu);
}
private static void checkBreakStatement(PsiBreakStatement breakStatement, DefiniteAssignment definiteAssignment) {
definiteAssignment.storeBeforeBreakStatement(breakStatement);
definiteAssignment.set(true, true);
}
private static void checkContinueStatement(PsiContinueStatement continueStatement, DefiniteAssignment definiteAssignment) {
definiteAssignment.storeBeforeContinueStatement(continueStatement);
definiteAssignment.set(true, true);
}
private static void checkDeclarationStatement(PsiDeclarationStatement declarationStatement, DefiniteAssignment definiteAssignment) {
for (PsiElement element : declarationStatement.getDeclaredElements()) {
if (element instanceof PsiLocalVariable) {
final PsiLocalVariable variable = (PsiLocalVariable)element;
checkLocalVariable(variable, definiteAssignment);
}
else if (element instanceof PsiClass) {
final PsiClass aClass = (PsiClass)element;
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
definiteAssignment.set(true, false);
checkClass(aClass, definiteAssignment);
definiteAssignment.set(da, du);
}
else {
throw new AssertionError("unknown element declared: " + element);
}
}
}
private static void checkDoWhileStatement(PsiDoWhileStatement doWhileStatement, DefiniteAssignment definiteAssignment) {
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
final PsiExpression condition = doWhileStatement.getCondition();
final PsiStatement body = doWhileStatement.getBody();
checkStatement(body, definiteAssignment);
checkExpression(condition, definiteAssignment, BooleanExpressionValue.WHEN_TRUE);
definiteAssignment.set(da, definiteAssignment.isDefinitelyUnassigned() & du);
checkStatement(body, definiteAssignment);
definiteAssignment.andDefiniteAssignmentBeforeContinue(doWhileStatement);
checkExpression(condition, definiteAssignment, BooleanExpressionValue.WHEN_FALSE);
definiteAssignment.andDefiniteAssignmentBeforeBreak(doWhileStatement);
}
private static void checkExpressionListStatement(PsiExpressionListStatement expressionListStatement,
DefiniteAssignment definiteAssignment) {
final PsiExpressionList expressionList = expressionListStatement.getExpressionList();
for (PsiExpression expression : expressionList.getExpressions()) {
checkExpression(expression, definiteAssignment, BooleanExpressionValue.UNDEFINED);
}
}
private static void checkForeachStatement(PsiForeachStatement foreachStatement, DefiniteAssignment definiteAssignment) {
checkExpression(foreachStatement.getIteratedValue(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
final boolean da = definiteAssignment.isDefinitelyAssigned();
checkStatement(foreachStatement.getBody(), definiteAssignment);
definiteAssignment.set(da, definiteAssignment.isDefinitelyUnassigned());
definiteAssignment.andDefiniteAssignmentBeforeBreak(foreachStatement);
}
private static void checkForStatement(PsiForStatement forStatement, DefiniteAssignment definiteAssignment) {
checkStatement(forStatement.getInitialization(), definiteAssignment);
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
final PsiExpression condition = forStatement.getCondition();
checkExpression(condition, definiteAssignment, BooleanExpressionValue.WHEN_TRUE);
checkStatement(forStatement.getBody(), definiteAssignment);
definiteAssignment.andDefiniteAssignmentBeforeContinue(forStatement);
checkStatement(forStatement.getUpdate(), definiteAssignment);
// hack because javac does not match spec for incrementation part of for statement
checkStatement(forStatement.getBody(), definiteAssignment);
definiteAssignment.set(da, du);
if (condition == null) {
definiteAssignment.set(true, true);
}
else {
checkExpression(condition, definiteAssignment, BooleanExpressionValue.WHEN_FALSE);
}
definiteAssignment.andDefiniteAssignmentBeforeBreak(forStatement);
}
private static void checkIfStatement(PsiIfStatement ifStatement, DefiniteAssignment definiteAssignment) {
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
final PsiExpression condition = ifStatement.getCondition();
checkExpression(condition, definiteAssignment, BooleanExpressionValue.WHEN_TRUE);
checkStatement(ifStatement.getThenBranch(), definiteAssignment);
final boolean resultDa = definiteAssignment.isDefinitelyAssigned();
final boolean resultDu = definiteAssignment.isDefinitelyUnassigned();
definiteAssignment.set(da, du);
checkExpression(condition, definiteAssignment, BooleanExpressionValue.WHEN_FALSE);
checkStatement(ifStatement.getElseBranch(), definiteAssignment);
definiteAssignment.and(resultDa, resultDu);
}
private static void checkLabeledStatement(PsiLabeledStatement labeledStatement, DefiniteAssignment definiteAssignment) {
final PsiStatement statement = labeledStatement.getStatement();
checkStatement(statement, definiteAssignment);
definiteAssignment.andDefiniteAssignmentBeforeBreak(statement);
}
private static void checkReturnStatement(PsiReturnStatement returnStatement, DefiniteAssignment definiteAssignment) {
definiteAssignment.storeBeforeReturn(returnStatement);
checkExpression(returnStatement.getReturnValue(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
definiteAssignment.set(true, true);
}
private static void checkSwitchStatement(PsiSwitchStatement switchStatement, DefiniteAssignment definiteAssignment) {
checkExpression(switchStatement.getExpression(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
final PsiCodeBlock body = switchStatement.getBody();
if (body == null) {
return;
}
final PsiStatement[] statements = body.getStatements();
if (statements.length == 0) {
return;
}
boolean defaultSeen = false;
for (final PsiStatement statement : statements) {
if (statement instanceof PsiSwitchLabelStatement) {
final PsiSwitchLabelStatement switchLabelStatement = (PsiSwitchLabelStatement)statement;
if (switchLabelStatement.isDefaultCase()) {
defaultSeen = true;
}
}
checkStatement(statement, definiteAssignment);
}
definiteAssignment.andDefiniteAssignmentBeforeBreak(switchStatement); // enum switch not specified
definiteAssignment.and(defaultSeen, definiteAssignment.isDefinitelyUnassigned());
}
private static void checkSynchronizedStatement(PsiSynchronizedStatement synchronizedStatement, DefiniteAssignment definiteAssignment) {
checkExpression(synchronizedStatement.getLockExpression(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
checkCodeBlock(synchronizedStatement.getBody(), definiteAssignment);
}
private static void checkThrowStatement(PsiThrowStatement throwStatement, DefiniteAssignment definiteAssignment) {
checkExpression(throwStatement.getException(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
definiteAssignment.set(true, true);
}
private static void checkTryStatement(PsiTryStatement tryStatement, DefiniteAssignment definiteAssignment) {
// try with resources not specified
final boolean da = definiteAssignment.isDefinitelyAssigned();
checkCodeBlock(tryStatement.getTryBlock(), definiteAssignment);
final boolean du = definiteAssignment.isDefinitelyUnassigned();
boolean resultDa = definiteAssignment.isDefinitelyAssigned();
boolean resultDu = du;
for (PsiCodeBlock catchBlock : tryStatement.getCatchBlocks()) {
definiteAssignment.set(da, du);
checkCodeBlock(catchBlock, definiteAssignment);
resultDu &= definiteAssignment.isDefinitelyUnassigned();
resultDa &= definiteAssignment.isDefinitelyAssigned();
}
final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
if (finallyBlock != null) {
definiteAssignment.set(da, definiteAssignment.isDefinitelyUnassigned());
checkCodeBlock(finallyBlock, definiteAssignment);
resultDu &= definiteAssignment.isDefinitelyUnassigned(); // spec problem
}
definiteAssignment.set(resultDa | definiteAssignment.isDefinitelyAssigned(), resultDu);
}
private static void checkWhileStatement(PsiWhileStatement whileStatement, DefiniteAssignment definiteAssignment) {
final boolean da = definiteAssignment.isDefinitelyAssigned();
final PsiExpression condition = whileStatement.getCondition();
checkExpression(condition, definiteAssignment, BooleanExpressionValue.WHEN_TRUE);
checkStatement(whileStatement.getBody(), definiteAssignment);
definiteAssignment.andDefiniteAssignmentBeforeContinue(whileStatement);
definiteAssignment.set(da, definiteAssignment.isDefinitelyUnassigned());
checkExpression(condition, definiteAssignment, BooleanExpressionValue.WHEN_FALSE);
definiteAssignment.andDefiniteAssignmentBeforeBreak(whileStatement);
}
private static void checkExpression(@Nullable PsiExpression expression,
DefiniteAssignment definiteAssignment,
BooleanExpressionValue value) {
if (expression == null || definiteAssignment.stop()) {
return;
}
if (PsiType.BOOLEAN.equals(expression.getType())) {
final Object result = ExpressionUtils.computeConstantExpression(expression);
if (Boolean.TRUE == result) {
if (BooleanExpressionValue.WHEN_FALSE == value) {
definiteAssignment.set(true, true);
}
return;
}
else if (Boolean.FALSE == result) {
if (BooleanExpressionValue.WHEN_TRUE == value) {
definiteAssignment.set(true, true);
}
return;
}
}
if (expression instanceof PsiArrayAccessExpression) {
final PsiArrayAccessExpression arrayAccessExpression = (PsiArrayAccessExpression)expression;
checkArrayAccessExpression(arrayAccessExpression, definiteAssignment, value);
}
else if (expression instanceof PsiArrayInitializerExpression) {
final PsiArrayInitializerExpression arrayInitializerExpression = (PsiArrayInitializerExpression)expression;
checkArrayInitializerExpression(arrayInitializerExpression, definiteAssignment, value);
}
else if (expression instanceof PsiAssignmentExpression) {
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expression;
checkAssignmentExpression(assignmentExpression, definiteAssignment);
}
else if (expression instanceof PsiConditionalExpression) {
final PsiConditionalExpression conditionalExpression = (PsiConditionalExpression)expression;
checkConditionalExpression(conditionalExpression, definiteAssignment, value);
}
else if (expression instanceof PsiInstanceOfExpression) {
final PsiInstanceOfExpression instanceOfExpression = (PsiInstanceOfExpression)expression;
checkExpression(instanceOfExpression.getOperand(), definiteAssignment, value);
}
else if (expression instanceof PsiMethodCallExpression) {
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
checkMethodCallExpression(methodCallExpression, definiteAssignment, value);
}
else if (expression instanceof PsiNewExpression) {
final PsiNewExpression newExpression = (PsiNewExpression)expression;
checkNewExpression(newExpression, definiteAssignment, value);
}
else if (expression instanceof PsiParenthesizedExpression) {
final PsiParenthesizedExpression parenthesizedExpression = (PsiParenthesizedExpression)expression;
checkExpression(parenthesizedExpression.getExpression(), definiteAssignment, value);
}
else if (expression instanceof PsiPolyadicExpression) {
final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)expression;
checkPolyadicExpression(polyadicExpression, definiteAssignment, value);
}
else if (expression instanceof PsiPostfixExpression) {
final PsiPostfixExpression postfixExpression = (PsiPostfixExpression)expression;
checkPostFixExpression(postfixExpression, definiteAssignment);
}
else if (expression instanceof PsiPrefixExpression) {
final PsiPrefixExpression prefixExpression = (PsiPrefixExpression)expression;
checkPrefixExpression(prefixExpression, definiteAssignment, value);
}
else if (expression instanceof PsiReferenceExpression) {
final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression;
checkReferenceExpression(referenceExpression, definiteAssignment, value);
}
else if (expression instanceof PsiTypeCastExpression) {
final PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression)expression;
checkExpression(typeCastExpression.getOperand(), definiteAssignment, value);
}
}
private static void checkArrayAccessExpression(PsiArrayAccessExpression arrayAccessExpression,
DefiniteAssignment definiteAssignment,
BooleanExpressionValue value) {
checkExpression(arrayAccessExpression.getArrayExpression(), definiteAssignment, value);
checkExpression(arrayAccessExpression.getIndexExpression(), definiteAssignment, value);
}
private static void checkArrayInitializerExpression(PsiArrayInitializerExpression arrayInitializerExpression,
DefiniteAssignment definiteAssignment,
BooleanExpressionValue value) {
for (PsiExpression initializer : arrayInitializerExpression.getInitializers()) {
checkExpression(initializer, definiteAssignment, value);
}
}
private static void checkAssignmentExpression(PsiAssignmentExpression assignmentExpression, DefiniteAssignment definiteAssignment) {
final PsiExpression lhs = assignmentExpression.getLExpression();
final PsiReferenceExpression referenceExpression = getReferenceIfAssignmentOfVariable(lhs, definiteAssignment);
if (referenceExpression == null) {
checkExpression(lhs, definiteAssignment, BooleanExpressionValue.UNDEFINED);
checkExpression(assignmentExpression.getRExpression(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
}
else {
final IElementType tokenType = assignmentExpression.getOperationTokenType();
if (!JavaTokenType.EQ.equals(tokenType)) {
definiteAssignment.valueAccess(referenceExpression);
}
checkExpression(assignmentExpression.getRExpression(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
definiteAssignment.assign(referenceExpression, true);
}
}
private static PsiReferenceExpression getReferenceIfAssignmentOfVariable(PsiExpression lhs, DefiniteAssignment definiteAssignment) {
lhs = ParenthesesUtils.stripParentheses(lhs);
if (!(lhs instanceof PsiReferenceExpression)) {
return null;
}
final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lhs;
final PsiElement target = referenceExpression.resolve();
if (!definiteAssignment.getVariable().equals(target)) {
return null;
}
final PsiExpression qualifier = referenceExpression.getQualifierExpression();
if (qualifier != null && (!(qualifier instanceof PsiThisExpression) || ((PsiThisExpression)qualifier).getQualifier() != null)) {
return null;
}
return referenceExpression;
}
private static void checkConditionalExpression(PsiConditionalExpression conditionalExpression,
DefiniteAssignment definiteAssignment,
BooleanExpressionValue value) {
final PsiExpression thenExpression = conditionalExpression.getThenExpression();
final PsiExpression elseExpression = conditionalExpression.getElseExpression();
if (thenExpression != null && PsiType.BOOLEAN.equals(thenExpression.getType()) &&
elseExpression != null && PsiType.BOOLEAN.equals(elseExpression.getType())) {
if (value == BooleanExpressionValue.WHEN_TRUE) {
checkConditionalInternal(conditionalExpression, definiteAssignment, BooleanExpressionValue.WHEN_TRUE);
}
else if (value == BooleanExpressionValue.WHEN_FALSE) {
checkConditionalInternal(conditionalExpression, definiteAssignment, BooleanExpressionValue.WHEN_FALSE);
}
else {
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
checkConditionalExpression(conditionalExpression, definiteAssignment, BooleanExpressionValue.WHEN_TRUE);
final boolean resultDa = definiteAssignment.isDefinitelyAssigned();
final boolean resultDu = definiteAssignment.isDefinitelyUnassigned();
definiteAssignment.set(da, du);
checkConditionalExpression(conditionalExpression, definiteAssignment, BooleanExpressionValue.WHEN_FALSE);
definiteAssignment.and(resultDa, resultDu);
}
}
else {
checkConditionalInternal(conditionalExpression, definiteAssignment, BooleanExpressionValue.UNDEFINED);
}
}
private static void checkConditionalInternal(PsiConditionalExpression conditionalExpression,
DefiniteAssignment definiteAssignment,
BooleanExpressionValue value) {
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
final PsiExpression condition = conditionalExpression.getCondition();
checkExpression(condition, definiteAssignment, BooleanExpressionValue.WHEN_TRUE);
checkExpression(conditionalExpression.getThenExpression(), definiteAssignment, value);
final boolean resultDa = definiteAssignment.isDefinitelyAssigned();
final boolean resultDu = definiteAssignment.isDefinitelyUnassigned();
definiteAssignment.set(da, du);
checkExpression(condition, definiteAssignment, BooleanExpressionValue.WHEN_FALSE);
checkExpression(conditionalExpression.getElseExpression(), definiteAssignment, value);
definiteAssignment.and(resultDa, resultDu);
}
private static void checkMethodCallExpression(PsiMethodCallExpression methodCallExpression,
DefiniteAssignment definiteAssignment,
BooleanExpressionValue value) {
final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
final PsiExpression qualifier = methodExpression.getQualifierExpression();
checkExpression(qualifier, definiteAssignment, value);
final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
for (PsiExpression argument : argumentList.getExpressions()) {
checkExpression(argument, definiteAssignment, value);
}
}
private static void checkNewExpression(PsiNewExpression newExpression,
DefiniteAssignment definiteAssignment,
BooleanExpressionValue value) {
final PsiExpressionList argumentList = newExpression.getArgumentList();
if (argumentList != null) {
for (PsiExpression argument : argumentList.getExpressions()) {
checkExpression(argument, definiteAssignment, value);
}
}
final PsiAnonymousClass anonymousClass = newExpression.getAnonymousClass();
if (anonymousClass != null) {
final boolean du = definiteAssignment.isDefinitelyUnassigned();
definiteAssignment.set(definiteAssignment.isDefinitelyAssigned(), false);
checkAnonymousClass(anonymousClass, definiteAssignment);
definiteAssignment.set(definiteAssignment.isDefinitelyAssigned(), du);
}
for (PsiExpression dimension : newExpression.getArrayDimensions()) {
checkExpression(dimension, definiteAssignment, value);
}
final PsiArrayInitializerExpression arrayInitializer = newExpression.getArrayInitializer();
if (arrayInitializer != null) {
checkExpression(arrayInitializer, definiteAssignment, value);
}
}
private static void checkPolyadicExpression(PsiPolyadicExpression polyadicExpression,
DefiniteAssignment definiteAssignment,
BooleanExpressionValue value) {
final PsiExpression[] operands = polyadicExpression.getOperands();
final IElementType tokenType = polyadicExpression.getOperationTokenType();
if (JavaTokenType.OROR == tokenType || JavaTokenType.ANDAND == tokenType) {
for (int i = 1; i < operands.length; i++) {
checkBinaryExpression(operands[i - 1], operands[i], tokenType == JavaTokenType.ANDAND, definiteAssignment, value);
}
}
else {
for (PsiExpression operand : operands) {
checkExpression(operand, definiteAssignment, BooleanExpressionValue.UNDEFINED);
}
}
}
private static void checkBinaryExpression(PsiExpression lhs,
PsiExpression rhs,
boolean and,
DefiniteAssignment definiteAssignment,
BooleanExpressionValue value) {
if (and ? value == BooleanExpressionValue.WHEN_FALSE : value == BooleanExpressionValue.WHEN_TRUE) {
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
checkExpression(lhs, definiteAssignment, and ? BooleanExpressionValue.WHEN_FALSE : BooleanExpressionValue.WHEN_TRUE);
final boolean resultDa = definiteAssignment.isDefinitelyAssigned();
final boolean resultDu = definiteAssignment.isDefinitelyUnassigned();
definiteAssignment.set(da, du);
checkExpression(lhs, definiteAssignment, and ? BooleanExpressionValue.WHEN_TRUE : BooleanExpressionValue.WHEN_FALSE);
checkExpression(rhs, definiteAssignment, and ? BooleanExpressionValue.WHEN_FALSE : BooleanExpressionValue.WHEN_TRUE);
definiteAssignment.and(resultDa, resultDu);
}
else if (and ? value == BooleanExpressionValue.WHEN_TRUE : value == BooleanExpressionValue.WHEN_FALSE) {
checkExpression(lhs, definiteAssignment, and ? BooleanExpressionValue.WHEN_TRUE : BooleanExpressionValue.WHEN_FALSE);
checkExpression(rhs, definiteAssignment, and ? BooleanExpressionValue.WHEN_TRUE : BooleanExpressionValue.WHEN_FALSE);
}
else {
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
checkBinaryExpression(lhs, rhs, false, definiteAssignment, BooleanExpressionValue.WHEN_TRUE);
final boolean resultDa = definiteAssignment.isDefinitelyAssigned();
final boolean resultDu = definiteAssignment.isDefinitelyUnassigned();
definiteAssignment.set(da, du);
checkBinaryExpression(lhs, rhs, false, definiteAssignment, BooleanExpressionValue.WHEN_FALSE);
definiteAssignment.and(resultDa, resultDu);
}
}
private static void checkPostFixExpression(PsiPostfixExpression postfixExpression, DefiniteAssignment definiteAssignment) {
checkExpression(postfixExpression.getOperand(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
}
private static void checkPrefixExpression(PsiPrefixExpression prefixExpression,
DefiniteAssignment definiteAssignment,
BooleanExpressionValue value) {
final IElementType tokenType = prefixExpression.getOperationTokenType();
if (JavaTokenType.EXCL == tokenType) {
if (value == BooleanExpressionValue.WHEN_TRUE) {
checkExpression(prefixExpression.getOperand(), definiteAssignment, BooleanExpressionValue.WHEN_FALSE);
}
else if (value == BooleanExpressionValue.WHEN_FALSE) {
checkExpression(prefixExpression.getOperand(), definiteAssignment, BooleanExpressionValue.WHEN_TRUE);
}
else {
final boolean da = definiteAssignment.isDefinitelyAssigned();
final boolean du = definiteAssignment.isDefinitelyUnassigned();
checkPrefixExpression(prefixExpression, definiteAssignment, BooleanExpressionValue.WHEN_TRUE);
final boolean resultDa = definiteAssignment.isDefinitelyAssigned();
final boolean resultDu = definiteAssignment.isDefinitelyUnassigned();
definiteAssignment.set(da, du);
checkPrefixExpression(prefixExpression, definiteAssignment, BooleanExpressionValue.WHEN_FALSE);
definiteAssignment.and(resultDa, resultDu);
}
}
else {
checkExpression(prefixExpression.getOperand(), definiteAssignment, BooleanExpressionValue.UNDEFINED);
}
}
private static void checkReferenceExpression(PsiReferenceExpression referenceExpression,
DefiniteAssignment definiteAssignment,
BooleanExpressionValue value) {
final PsiExpression qualifier = referenceExpression.getQualifierExpression();
if (qualifier != null) {
checkExpression(qualifier, definiteAssignment, value);
}
if (!definiteAssignment.getVariable().equals(referenceExpression.resolve())) {
return;
}
if (PsiUtil.isAccessedForWriting(referenceExpression)) {
definiteAssignment.assign(referenceExpression, false);
}
else {
if (qualifier != null) {
if (!(qualifier instanceof PsiThisExpression)) {
return;
}
final PsiThisExpression thisExpression = (PsiThisExpression)qualifier;
if (thisExpression.getQualifier() != null) {
return;
}
}
definiteAssignment.valueAccess(referenceExpression);
}
}
private enum BooleanExpressionValue {
WHEN_TRUE, WHEN_FALSE, UNDEFINED
}
}