modularize literal constructor search a bit

This commit is contained in:
peter
2010-07-30 12:58:52 +01:00
parent a57110b586
commit e7f8ead4fc
2 changed files with 106 additions and 90 deletions
@@ -47,15 +47,12 @@ import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
import org.jetbrains.plugins.groovy.gpp.GppTypeConverter;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
@@ -67,9 +64,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.GroovyExpectedTypesProvider;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import java.util.Arrays;
import java.util.HashSet;
@@ -111,13 +105,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase<PsiRefere
}
}
final PairProcessor<GrListOrMap, PsiClassType> literalProcessor = new PairProcessor<GrListOrMap, PsiClassType>() {
@Override
public boolean process(GrListOrMap list, PsiClassType expectedType) {
return checkLiteralInstantiation(constructor, consumer, list, expectedType);
}
};
final LiteralConstructorSearcher literalProcessor = new LiteralConstructorSearcher(constructor, consumer);
final Processor<GrNewExpression> newExpressionProcessor = new Processor<GrNewExpression>() {
@Override
@@ -155,7 +143,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase<PsiRefere
SearchRequestCollector collector,
final boolean searchGppCalls,
final Processor<GrNewExpression> newExpressionProcessor,
final PairProcessor<GrListOrMap, PsiClassType> literalProcessor) {
final LiteralConstructorSearcher literalProcessor) {
final Set<PsiMethod> processedMethods = new ConcurrentHashSet<PsiMethod>();
ReferencesSearch.searchOptimized(clazz, scope, true, collector, true, new PairProcessor<PsiReference, SearchRequestCollector>() {
@@ -200,7 +188,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase<PsiRefere
private static void processGppMethodCalls(final PsiClass targetClass,
SearchScope scope,
SearchRequestCollector originalCollector, @NotNull PsiMethod currentTarget,
final PairProcessor<GrListOrMap, PsiClassType> literalProcessor) {
final LiteralConstructorSearcher literalProcessor) {
final SearchScope gppScope = getGppScope(targetClass.getProject()).intersectWith(scope);
final ReadActionProcessor<PsiReference> gppCallProcessor = new ReadActionProcessor<PsiReference>() {
@Override
@@ -224,7 +212,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase<PsiRefere
for (PsiType psiType : GroovyExpectedTypesProvider.getDefaultExpectedTypes(argument)) {
if (psiType instanceof PsiClassType &&
targetClass.getManager().areElementsEquivalent(targetClass, ((PsiClassType)psiType).resolve()) &&
!literalProcessor.process((GrListOrMap)argument, (PsiClassType)psiType)) {
!literalProcessor.processLiteral((GrListOrMap)argument, (PsiClassType)psiType)) {
return false;
}
}
@@ -256,7 +244,7 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase<PsiRefere
private static boolean processGroovyConstructorUsages(GrCodeReferenceElement element,
boolean usualCallsOnly,
final Processor<GrNewExpression> newExpressionProcessor,
final PairProcessor<GrListOrMap, PsiClassType> literalProcessor) {
final LiteralConstructorSearcher literalProcessor) {
PsiElement parent = element.getParent();
if (parent instanceof GrAnonymousClassDefinition) {
@@ -344,88 +332,17 @@ public class GroovyConstructorUsagesSearcher extends QueryExecutorBase<PsiRefere
private static boolean checkLiteralInstantiation(GrExpression expression,
final GrTypeElement typeElement,
final PairProcessor<GrListOrMap, PsiClassType> literalProcessor) {
final LiteralConstructorSearcher literalProcessor) {
if (expression instanceof GrListOrMap) {
final PsiType expectedType = typeElement.getType();
if (expectedType instanceof PsiClassType) {
return literalProcessor.process((GrListOrMap)expression, (PsiClassType)expectedType);
return literalProcessor.processLiteral((GrListOrMap)expression, (PsiClassType)expectedType);
}
}
return true;
}
private static boolean checkLiteralInstantiation(PsiMethod constructor,
Processor<PsiReference> consumer,
GrListOrMap literal,
PsiClassType expectedType) {
final PsiType listType = literal.getType();
if (listType instanceof GrTupleType) {
if (isConstructorCall(expectedType, ((GrTupleType)listType).getComponentTypes(), constructor, literal)) {
return consumer.process(PsiReferenceBase.createSelfReference(literal, TextRange.from(0, literal.getTextLength()), constructor));
}
}
else if (listType instanceof GrMapType) {
final PsiType constructorArgs = ((GrMapType)listType).getValueType("super");
if (constructorArgs == null) {
if (constructor.getParameterList().getParametersCount() == 0) {
if (!consumer.process(PsiReferenceBase.createSelfReference(literal, TextRange.from(0, literal.getTextLength()), constructor))) {
return false;
}
}
return true;
}
for (GrNamedArgument argument : literal.getNamedArguments()) {
final GrArgumentLabel label = argument.getLabel();
if (label != null && "super".equals(label.getName())) {
if (mayInvokeConstructor(expectedType, constructor, argument.getExpression())) {
return consumer.process(PsiReferenceBase.createSelfReference(label, TextRange.from(0, label.getTextLength()), constructor));
}
return true;
}
}
//no 'super', only default constructor applicable
if (constructor.getParameterList().getParametersCount() == 0) {
return consumer.process(PsiReferenceBase.createSelfReference(literal, TextRange.from(0, literal.getTextLength()), constructor));
}
}
return true;
}
private static boolean mayInvokeConstructor(PsiClassType expectedType, PsiMethod constructor, GrExpression args) {
if (args == null) {
return true;
}
final PsiType type = args.getType();
if (type == null) {
return true;
}
if (type instanceof GrTupleType) {
if (!isConstructorCall(expectedType, ((GrTupleType)type).getComponentTypes(), constructor, args)) {
return false;
}
} else if (!isConstructorCall(expectedType, new PsiType[]{type}, constructor, args)) {
return false;
}
return true;
}
private static boolean isConstructorCall(PsiClassType expectedType,
PsiType[] argTypes,
PsiMethod constructor,
GroovyPsiElement context) {
for (GroovyResolveResult candidate : PsiUtil.getConstructorCandidates(expectedType, argTypes, context)) {
if (constructor.getManager().areElementsEquivalent(candidate.getElement(), constructor)) {
return true;
}
}
return false;
}
private static boolean processConstructors(final PsiMethod searchedConstructor, final Processor<PsiReference> consumer, final PsiClass clazz,
final boolean processThisRefs) {
final PsiMethod[] constructors = clazz.getConstructors();
@@ -0,0 +1,99 @@
package org.jetbrains.plugins.groovy.findUsages;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.util.Processor;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
/**
* @author peter
*/
class LiteralConstructorSearcher {
private final PsiMethod myConstructor;
private final Processor<PsiReference> myConsumer;
public LiteralConstructorSearcher(PsiMethod constructor, Processor<PsiReference> consumer) {
myConstructor = constructor;
myConsumer = consumer;
}
private static boolean checkLiteralInstantiation(PsiMethod constructor,
Processor<PsiReference> consumer,
GrListOrMap literal,
PsiClassType expectedType) {
final PsiType listType = literal.getType();
if (listType instanceof GrTupleType) {
if (isConstructorCall(expectedType, ((GrTupleType)listType).getComponentTypes(), constructor, literal)) {
return consumer.process(PsiReferenceBase.createSelfReference(literal, TextRange.from(0, literal.getTextLength()), constructor));
}
}
else if (listType instanceof GrMapType) {
final PsiType constructorArgs = ((GrMapType)listType).getValueType("super");
if (constructorArgs == null) {
if (constructor.getParameterList().getParametersCount() == 0) {
if (!consumer.process(PsiReferenceBase.createSelfReference(literal, TextRange.from(0, literal.getTextLength()), constructor))) {
return false;
}
}
return true;
}
for (GrNamedArgument argument : literal.getNamedArguments()) {
final GrArgumentLabel label = argument.getLabel();
if (label != null && "super".equals(label.getName())) {
if (mayInvokeConstructor(expectedType, constructor, argument.getExpression())) {
return consumer.process(PsiReferenceBase.createSelfReference(label, TextRange.from(0, label.getTextLength()), constructor));
}
return true;
}
}
//no 'super', only default constructor applicable
if (constructor.getParameterList().getParametersCount() == 0) {
return consumer.process(PsiReferenceBase.createSelfReference(literal, TextRange.from(0, literal.getTextLength()), constructor));
}
}
return true;
}
private static boolean mayInvokeConstructor(PsiClassType expectedType, PsiMethod constructor, GrExpression args) {
if (args == null) {
return true;
}
final PsiType type = args.getType();
if (type == null) {
return true;
}
if (type instanceof GrTupleType) {
return isConstructorCall(expectedType, ((GrTupleType)type).getComponentTypes(), constructor, args);
}
return isConstructorCall(expectedType, new PsiType[]{type}, constructor, args);
}
private static boolean isConstructorCall(PsiClassType expectedType,
PsiType[] argTypes,
PsiMethod constructor,
GroovyPsiElement context) {
for (GroovyResolveResult candidate : PsiUtil.getConstructorCandidates(expectedType, argTypes, context)) {
if (constructor.getManager().areElementsEquivalent(candidate.getElement(), constructor)) {
return true;
}
}
return false;
}
public boolean processLiteral(GrListOrMap list, PsiClassType expectedType) {
return checkLiteralInstantiation(myConstructor, myConsumer, list, expectedType);
}
}