highlighting optimizations

This commit is contained in:
Alexey Kudravtsev
2011-09-07 12:06:38 +04:00
parent 029d94b279
commit aa4a91edae
5 changed files with 80 additions and 55 deletions
@@ -422,8 +422,7 @@ public class HighlightControlFlowUtil {
}
public static boolean isReassigned(PsiVariable variable,
Map<PsiElement, Collection<ControlFlowUtil.VariableInfo>> finalVarProblems,
Map<PsiParameter, Boolean> parameterIsReassigned) {
Map<PsiElement, Collection<ControlFlowUtil.VariableInfo>> finalVarProblems) {
if (variable instanceof PsiLocalVariable) {
final PsiElement parent = variable.getParent();
if (parent == null) return false;
@@ -433,11 +432,7 @@ public class HighlightControlFlowUtil {
}
else if (variable instanceof PsiParameter) {
final PsiParameter parameter = (PsiParameter)variable;
final Boolean isReassigned = parameterIsReassigned.get(parameter);
if (isReassigned != null) return isReassigned.booleanValue();
boolean isAssigned = PsiUtil.isAssigned(parameter);
parameterIsReassigned.put(parameter, Boolean.valueOf(isAssigned));
return isAssigned;
return PsiUtil.isAssigned(parameter);
}
else {
return false;
@@ -143,17 +143,15 @@ public class HighlightNamesUtil {
|| var instanceof PsiParameter && ((PsiParameter)var).getDeclarationScope() instanceof PsiForeachStatement) {
return HighlightInfoType.LOCAL_VARIABLE;
}
else if (var instanceof PsiField) {
if (var instanceof PsiField) {
return var.hasModifierProperty(PsiModifier.STATIC)
? HighlightInfoType.STATIC_FIELD
: HighlightInfoType.INSTANCE_FIELD;
}
else if (var instanceof PsiParameter) {
if (var instanceof PsiParameter) {
return HighlightInfoType.PARAMETER;
}
else { //?
return null;
}
return null;
}
private static HighlightInfoType getClassNameHighlightType(PsiClass aClass) {
@@ -884,14 +884,13 @@ public class HighlightUtil {
@Nullable
static HighlightInfo checkMustBeBoolean(PsiExpression expr) {
static HighlightInfo checkMustBeBoolean(@NotNull PsiExpression expr, PsiType type) {
PsiElement parent = expr.getParent();
if (parent instanceof PsiIfStatement || parent instanceof PsiWhileStatement ||
parent instanceof PsiForStatement && expr.equals(((PsiForStatement)parent).getCondition()) ||
parent instanceof PsiDoWhileStatement && expr.equals(((PsiDoWhileStatement)parent).getCondition())) {
if (expr.getNextSibling() instanceof PsiErrorElement) return null;
PsiType type = expr.getType();
if (!TypeConversionUtil.isBooleanType(type)) {
final HighlightInfo info = createIncompatibleTypeHighlightInfo(PsiType.BOOLEAN, type, expr.getTextRange());
if (expr instanceof PsiMethodCallExpression) {
@@ -1225,7 +1224,7 @@ public class HighlightUtil {
}
@Nullable
static HighlightInfo checkValidArrayAccessExpression(PsiExpression arrayExpression, PsiExpression indexExpression) {
static HighlightInfo checkValidArrayAccessExpression(PsiExpression arrayExpression, PsiExpression indexExpression, PsiType type) {
PsiType arrayExpressionType = arrayExpression == null ? null : arrayExpression.getType();
if (arrayExpressionType != null && !(arrayExpressionType instanceof PsiArrayType)) {
String description = JavaErrorMessages.message("array.type.expected", formatType(arrayExpressionType));
@@ -1255,13 +1254,11 @@ public class HighlightUtil {
}
@Nullable
public static Collection<HighlightInfo> checkArrayInitializer(final PsiExpression initializer) {
if (! (initializer instanceof PsiArrayInitializerExpression)) return null;
public static Collection<HighlightInfo> checkArrayInitializer(final PsiExpression initializer, PsiType type) {
if (!(initializer instanceof PsiArrayInitializerExpression)) return null;
if (!(type instanceof PsiArrayType)) return null;
final PsiType arrayInitializerType = initializer.getType();
if (! (arrayInitializerType instanceof PsiArrayType)) return null;
final PsiType componentType = ((PsiArrayType) arrayInitializerType).getComponentType();
final PsiType componentType = ((PsiArrayType) type).getComponentType();
final PsiArrayInitializerExpression arrayInitializer = (PsiArrayInitializerExpression) initializer;
boolean arrayTypeFixChecked = false;
@@ -1895,12 +1892,10 @@ public class HighlightUtil {
@Nullable
public static HighlightInfo checkTernaryOperatorConditionIsBoolean(PsiExpression expression) {
public static HighlightInfo checkTernaryOperatorConditionIsBoolean(PsiExpression expression, PsiType type) {
if (expression.getParent() instanceof PsiConditionalExpression &&
((PsiConditionalExpression)expression.getParent()).getCondition() == expression && expression.getType() != null &&
!TypeConversionUtil.isBooleanType(expression.getType())) {
PsiType foundType = expression.getType();
return createIncompatibleTypeHighlightInfo(PsiType.BOOLEAN, foundType, expression.getTextRange());
((PsiConditionalExpression)expression.getParent()).getCondition() == expression && !TypeConversionUtil.isBooleanType(type)) {
return createIncompatibleTypeHighlightInfo(PsiType.BOOLEAN, type, expression.getTextRange());
}
return null;
}
@@ -1920,18 +1915,17 @@ public class HighlightUtil {
@Nullable
public static HighlightInfo checkAssertOperatorTypes(PsiExpression expression) {
public static HighlightInfo checkAssertOperatorTypes(PsiExpression expression, PsiType type) {
if (type == null) return null;
if (!(expression.getParent() instanceof PsiAssertStatement)) {
return null;
}
PsiAssertStatement assertStatement = (PsiAssertStatement)expression.getParent();
PsiType type = expression.getType();
if (type == null) return null;
if (expression == assertStatement.getAssertCondition() && !TypeConversionUtil.isBooleanType(type)) {
// addTypeCast quickfix is not applicable here since no type can be cast to boolean
return createIncompatibleTypeHighlightInfo(PsiType.BOOLEAN, type, expression.getTextRange());
}
else if (expression == assertStatement.getAssertDescription() && TypeConversionUtil.isVoidType(type)) {
if (expression == assertStatement.getAssertDescription() && TypeConversionUtil.isVoidType(type)) {
String description = JavaErrorMessages.message("void.type.is.not.allowed");
return HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, expression, description);
}
@@ -1940,10 +1934,9 @@ public class HighlightUtil {
@Nullable
public static HighlightInfo checkSynchronizedExpressionType(PsiExpression expression) {
public static HighlightInfo checkSynchronizedExpressionType(PsiExpression expression, PsiType type) {
if (type == null) return null;
if (expression.getParent() instanceof PsiSynchronizedStatement) {
PsiType type = expression.getType();
if (type == null) return null;
PsiSynchronizedStatement synchronizedStatement = (PsiSynchronizedStatement)expression.getParent();
if (expression == synchronizedStatement.getLockExpression() &&
(type instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(type))) {
@@ -1956,17 +1949,18 @@ public class HighlightUtil {
@Nullable
public static HighlightInfo checkConditionalExpressionBranchTypesMatch(PsiExpression expression) {
if (!(expression.getParent() instanceof PsiConditionalExpression)) {
public static HighlightInfo checkConditionalExpressionBranchTypesMatch(final PsiExpression expression, PsiType type) {
PsiElement parent = expression.getParent();
if (!(parent instanceof PsiConditionalExpression)) {
return null;
}
PsiConditionalExpression conditionalExpression = (PsiConditionalExpression)expression.getParent();
PsiConditionalExpression conditionalExpression = (PsiConditionalExpression)parent;
// check else branches only
if (conditionalExpression.getElseExpression() != expression) return null;
final PsiExpression thenExpression = conditionalExpression.getThenExpression();
assert thenExpression != null;
PsiType thenType = thenExpression.getType();
PsiType elseType = expression.getType();
PsiType elseType = type;
if (thenType == null || elseType == null) return null;
if (conditionalExpression.getType() == null) {
// cannot derive type of conditional expression
@@ -44,6 +44,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.xml.XmlAttributeValue;
import gnu.trove.THashMap;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@@ -64,7 +65,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
private final Map<PsiElement, Collection<PsiReferenceExpression>> myUninitializedVarProblems = new THashMap<PsiElement, Collection<PsiReferenceExpression>>();
// map codeBlock->List of PsiReferenceExpression of extra initialization of final variable
private final Map<PsiElement, Collection<ControlFlowUtil.VariableInfo>> myFinalVarProblems = new THashMap<PsiElement, Collection<ControlFlowUtil.VariableInfo>>();
private final Map<PsiParameter, Boolean> myParameterIsReassigned = new THashMap<PsiParameter, Boolean>();
// value==1: no info if the parameter was reassigned (but the parameter is present in current file), value==2: parameter was reassigned
private final TObjectIntHashMap<PsiParameter> myReassignedParameters = new TObjectIntHashMap<PsiParameter>();
private final Map<String, Pair<PsiImportStaticReferenceElement, PsiClass>> mySingleImportedClasses = new THashMap<String, Pair<PsiImportStaticReferenceElement, PsiClass>>();
private final Map<String, Pair<PsiImportStaticReferenceElement, PsiField>> mySingleImportedFields = new THashMap<String, Pair<PsiImportStaticReferenceElement, PsiField>>();
@@ -144,7 +147,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
myFinalVarProblems.clear();
mySingleImportedClasses.clear();
mySingleImportedFields.clear();
myParameterIsReassigned.clear();
myReassignedParameters.clear();
myRefCountHolder = null;
myFile = null;
@@ -329,29 +332,31 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
ProgressManager.checkCanceled(); // visitLiteralExpression is invoked very often in array initializers
super.visitExpression(expression);
if (myHolder.add(HighlightUtil.checkMustBeBoolean(expression))) return;
PsiType type = expression.getType();
if (myHolder.add(HighlightUtil.checkMustBeBoolean(expression, type))) return;
PsiExpression indexExpression;
if (expression instanceof PsiArrayAccessExpression
&& ((PsiArrayAccessExpression)expression).getIndexExpression() != null) {
myHolder.add(HighlightUtil.checkValidArrayAccessExpression(((PsiArrayAccessExpression)expression).getArrayExpression(),
((PsiArrayAccessExpression)expression).getIndexExpression()));
&& (indexExpression = ((PsiArrayAccessExpression)expression).getIndexExpression()) != null) {
PsiExpression arrayExpression = ((PsiArrayAccessExpression)expression).getArrayExpression();
myHolder.add(HighlightUtil.checkValidArrayAccessExpression(arrayExpression, indexExpression, indexExpression.getType()));
}
if (expression.getParent() instanceof PsiNewExpression
&& ((PsiNewExpression)expression.getParent()).getQualifier() != expression
&& ((PsiNewExpression)expression.getParent()).getArrayInitializer() != expression) {
// like in 'new String["s"]'
myHolder.add(HighlightUtil.checkValidArrayAccessExpression(null, expression));
myHolder.add(HighlightUtil.checkValidArrayAccessExpression(null, expression, type));
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightControlFlowUtil.checkCannotWriteToFinal(expression));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkVariableExpected(expression));
if (!myHolder.hasErrorResults()) myHolder.addAll(HighlightUtil.checkArrayInitializer(expression));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTernaryOperatorConditionIsBoolean(expression));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAssertOperatorTypes(expression));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSynchronizedExpressionType(expression));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkConditionalExpressionBranchTypesMatch(expression));
if (!myHolder.hasErrorResults()) myHolder.addAll(HighlightUtil.checkArrayInitializer(expression, type));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkTernaryOperatorConditionIsBoolean(expression, type));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkAssertOperatorTypes(expression, type));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSynchronizedExpressionType(expression, type));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkConditionalExpressionBranchTypesMatch(expression, type));
if (!myHolder.hasErrorResults()
&& expression.getParent() instanceof PsiThrowStatement
&& ((PsiThrowStatement)expression.getParent()).getException() == expression) {
PsiType type = expression.getType();
myHolder.add(HighlightUtil.checkMustBeThrowable(type, expression, true));
}
@@ -392,11 +397,17 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
final PsiElement child = variable.getLastChild();
if (child instanceof PsiErrorElement && child.getPrevSibling() == identifier) return;
}
if (isReassigned(variable)) {
myHolder.add(HighlightNamesUtil.highlightReassignedVariable(variable, variable.getNameIdentifier()));
boolean isMethodParameter = variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() instanceof PsiMethod;
if (!isMethodParameter) { // method params are highlighted in visitMethod since we should make sure the method body was visited before
if (HighlightControlFlowUtil.isReassigned(variable, myFinalVarProblems)) {
myHolder.add(HighlightNamesUtil.highlightReassignedVariable(variable, identifier));
}
else {
myHolder.add(HighlightNamesUtil.highlightVariableName(variable, identifier, colorsScheme));
}
}
else {
myHolder.add(HighlightNamesUtil.highlightVariableName(variable, identifier, colorsScheme));
myReassignedParameters.put((PsiParameter)variable, 1); // mark param as present in current file
}
}
else if (parent instanceof PsiClass) {
@@ -566,6 +577,21 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!myHolder.hasErrorResults() && method.isConstructor()) {
myHolder.add(HighlightClassUtil.checkThingNotAllowedInInterface(method, method.getContainingClass()));
}
// method params are highlighted in visitMethod since we should make sure the method body was visited before
PsiParameter[] parameters = method.getParameterList().getParameters();
final EditorColorsScheme colorsScheme = myHolder.getColorsScheme();
for (PsiParameter parameter : parameters) {
int info = myReassignedParameters.get(parameter);
if (info == 0) continue; // out of this file
if (info == 2) {// reassigned
myHolder.add(HighlightNamesUtil.highlightReassignedVariable(parameter, parameter.getNameIdentifier()));
}
else {
myHolder.add(HighlightNamesUtil.highlightVariableName(parameter, parameter.getNameIdentifier(), colorsScheme));
}
}
}
private void highlightReferencedMethodOrClassName(PsiJavaCodeReferenceElement element, PsiElement resolved) {
@@ -792,6 +818,10 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
}
}
if (variable instanceof PsiParameter && ref instanceof PsiExpression && PsiUtil.isAccessedForWriting((PsiExpression)ref)) {
myReassignedParameters.put((PsiParameter)variable, 2);
}
final EditorColorsScheme colorsScheme = myHolder.getColorsScheme();
if (!variable.hasModifierProperty(PsiModifier.FINAL) && isReassigned(variable)) {
myHolder.add(HighlightNamesUtil.highlightReassignedVariable(variable, ref));
@@ -976,7 +1006,15 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
private boolean isReassigned(PsiVariable variable) {
try {
return HighlightControlFlowUtil.isReassigned(variable, myFinalVarProblems, myParameterIsReassigned);
boolean reassigned;
if (variable instanceof PsiParameter) {
reassigned = myReassignedParameters.get((PsiParameter)variable) == 2;
}
else {
reassigned = HighlightControlFlowUtil.isReassigned(variable, myFinalVarProblems);
}
return reassigned;
}
catch (IndexNotReadyException e) {
return false;
@@ -418,7 +418,7 @@ public class RefactoringUtil {
public static boolean canBeDeclaredFinal(PsiVariable variable) {
LOG.assertTrue(variable instanceof PsiLocalVariable || variable instanceof PsiParameter);
final boolean isReassigned = HighlightControlFlowUtil
.isReassigned(variable, new THashMap<PsiElement, Collection<ControlFlowUtil.VariableInfo>>(), new THashMap<PsiParameter, Boolean>());
.isReassigned(variable, new THashMap<PsiElement, Collection<ControlFlowUtil.VariableInfo>>());
return !isReassigned;
}