casting completion: don't run dfa when there are no suspicious casts, when dfa fails, offer all possible casts

This commit is contained in:
Peter Gromov
2009-09-16 18:22:07 +04:00
parent 9b2bae5c9c
commit 1e7e771af0
4 changed files with 80 additions and 16 deletions
@@ -118,7 +118,7 @@ public class BasicExpressionCompletionContributor extends ExpressionSmartComplet
final PsiExpression context = PsiTreeUtil.getParentOfType(position, PsiExpression.class);
if (context == null) return;
final Map<PsiExpression,PsiType> map = GuessManager.getInstance(position.getProject()).getDataFlowExpressionTypes(context);
final Map<PsiExpression,PsiType> map = GuessManager.getInstance(position.getProject()).getControlFlowExpressionTypes(context);
for (final PsiExpression expression : map.keySet()) {
final PsiType castType = map.get(expression);
final PsiType baseType = expression.getType();
@@ -870,7 +870,7 @@ public class JavaCompletionUtil {
type = evaluator.fun(qualifier, parameters);
}
if (type == null) {
type = GuessManager.getInstance(project).getDataFlowCastedExpressionType(qualifier);
type = GuessManager.getInstance(project).getControlFlowExpressionType(qualifier);
}
if (type != null) {
processor.clear();
@@ -21,10 +21,8 @@ public abstract class GuessManager {
public abstract PsiType[] guessTypeToCast(PsiExpression expr);
@NotNull
public abstract Map<PsiExpression, PsiType> getDataFlowExpressionTypes(@NotNull PsiExpression forPlace);
public abstract Map<PsiExpression, PsiType> getControlFlowExpressionTypes(@NotNull PsiExpression forPlace);
@Nullable
public PsiType getDataFlowCastedExpressionType(@NotNull PsiExpression expr) {
return getDataFlowExpressionTypes(expr).get(expr);
}
public abstract PsiType getControlFlowExpressionType(@NotNull PsiExpression expr);
}
@@ -17,6 +17,7 @@ import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
@@ -102,7 +103,7 @@ public class GuessManagerImpl extends GuessManager {
public PsiType[] guessTypeToCast(PsiExpression expr) { //TODO : make better guess based on control flow
LinkedHashSet<PsiType> types = new LinkedHashSet<PsiType>();
ContainerUtil.addIfNotNull(_getDataFlowExpressionTypes(expr).get(expr), types);
ContainerUtil.addIfNotNull(getControlFlowExpressionType(expr), types);
addExprTypesWhenContainerElement(types, expr);
addExprTypesByDerivedClasses(types, expr);
@@ -111,12 +112,17 @@ public class GuessManagerImpl extends GuessManager {
@NotNull
@Override
public Map<PsiExpression, PsiType> getDataFlowExpressionTypes(@NotNull final PsiExpression forPlace) {
return _getDataFlowExpressionTypes(forPlace);
public Map<PsiExpression, PsiType> getControlFlowExpressionTypes(@NotNull final PsiExpression forPlace) {
final Map<PsiExpression, PsiType> typeMap = buildDataflowTypeMap(forPlace);
if (typeMap != null) {
return typeMap;
}
return getAllTypeCasts(forPlace);
}
@NotNull
private static Map<PsiExpression, PsiType> _getDataFlowExpressionTypes(final PsiExpression forPlace) {
@Nullable
private static Map<PsiExpression, PsiType> buildDataflowTypeMap(PsiExpression forPlace) {
PsiElement scope = DfaUtil.getTopmostBlockInSameClass(forPlace);
if (scope == null) {
return Collections.emptyMap();
@@ -130,12 +136,57 @@ public class GuessManagerImpl extends GuessManager {
final ExpressionTypeInstructionVisitor visitor = new ExpressionTypeInstructionVisitor(forPlace);
if (runner.analyzeMethod(scope, visitor) == RunnerResult.OK) {
final Map<PsiExpression, PsiType> map = visitor.getResult();
if (map != null) {
return map;
}
return visitor.getResult();
}
return Collections.emptyMap();
return null;
}
private static Map<PsiExpression, PsiType> getAllTypeCasts(PsiExpression forPlace) {
final int start = forPlace.getTextRange().getStartOffset();
final Map<PsiExpression, PsiType> allCasts = new THashMap<PsiExpression, PsiType>(ExpressionTypeMemoryState.EXPRESSION_HASHING_STRATEGY);
getTopmostBlock(forPlace).accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitTypeCastExpression(PsiTypeCastExpression expression) {
final PsiTypeElement castType = expression.getCastType();
final PsiExpression operand = expression.getOperand();
if (operand != null && castType != null) {
allCasts.put(operand, castType.getType());
}
super.visitTypeCastExpression(expression);
}
@Override
public void visitInstanceOfExpression(PsiInstanceOfExpression expression) {
final PsiTypeElement castType = expression.getCheckType();
final PsiExpression operand = expression.getOperand();
if (castType != null) {
allCasts.put(operand, castType.getType());
}
super.visitInstanceOfExpression(expression);
}
@Override
public void visitElement(PsiElement element) {
if (element.getTextRange().getStartOffset() > start) {
return;
}
super.visitElement(element);
}
});
return allCasts;
}
private static PsiElement getTopmostBlock(PsiElement scope) {
PsiElement lastScope = scope;
while (true) {
final PsiCodeBlock lastCodeBlock = PsiTreeUtil.getParentOfType(lastScope, PsiCodeBlock.class, true);
if (lastCodeBlock == null) {
break;
}
lastScope = lastCodeBlock;
}
return lastScope;
}
private void addExprTypesByDerivedClasses(LinkedHashSet<PsiType> set, PsiExpression expr) {
@@ -293,6 +344,21 @@ public class GuessManagerImpl extends GuessManager {
return null;
}
@Nullable
public PsiType getControlFlowExpressionType(@NotNull PsiExpression expr) {
final Map<PsiExpression, PsiType> allCasts = getAllTypeCasts(expr);
if (!allCasts.containsKey(expr)) {
return null; //optimization
}
final Map<PsiExpression, PsiType> fromDfa = buildDataflowTypeMap(expr);
if (fromDfa != null) {
return fromDfa.get(expr);
}
return allCasts.get(expr);
}
private static class ExpressionTypeInstructionVisitor extends InstructionVisitor {
private Map<PsiExpression, PsiType> myResult;
private PsiElement myForPlace;