mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-63669 Groovy: [ .. ].property is the same as [ .. ]*.property
This commit is contained in:
+2
-1
@@ -61,7 +61,8 @@ public class GDKSuperMethodSearcher implements QueryExecutor<MethodSignatureBack
|
||||
|
||||
final String name = method.getName();
|
||||
final MethodResolverProcessor processor = new MethodResolverProcessor(name, ((GrMethod)method), false, null, null, PsiType.EMPTY_ARRAY);
|
||||
ResolveUtil.processNonCodeMembers(JavaPsiFacade.getElementFactory(project).createType(psiClass), processor, (GrMethod)method);
|
||||
ResolveUtil.processNonCodeMembers(JavaPsiFacade.getElementFactory(project).createType(psiClass), processor, (GrMethod)method,
|
||||
ResolveState.initial());
|
||||
|
||||
final GroovyResolveResult[] candidates = processor.getCandidates();
|
||||
|
||||
|
||||
+12
-1
@@ -15,9 +15,10 @@
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.lang.psi.api;
|
||||
|
||||
import com.intellij.psi.ResolveResult;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiSubstitutor;
|
||||
import com.intellij.psi.ResolveResult;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
|
||||
@@ -34,10 +35,14 @@ public interface GroovyResolveResult extends ResolveResult {
|
||||
@Nullable
|
||||
GroovyPsiElement getCurrentFileResolveContext();
|
||||
|
||||
@NotNull
|
||||
PsiSubstitutor getSubstitutor();
|
||||
|
||||
boolean isInvokedOnProperty();
|
||||
|
||||
@Nullable
|
||||
SpreadState getSpreadState();
|
||||
|
||||
GroovyResolveResult EMPTY_RESULT = new GroovyResolveResult() {
|
||||
public boolean isAccessible() {
|
||||
return false;
|
||||
@@ -51,6 +56,7 @@ public interface GroovyResolveResult extends ResolveResult {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor getSubstitutor() {
|
||||
return PsiSubstitutor.EMPTY;
|
||||
}
|
||||
@@ -68,5 +74,10 @@ public interface GroovyResolveResult extends ResolveResult {
|
||||
public boolean isInvokedOnProperty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpreadState getSpreadState() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 org.jetbrains.plugins.groovy.lang.psi.api;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.PsiType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
|
||||
|
||||
/**
|
||||
* @author Max Medvedev
|
||||
*/
|
||||
public final class SpreadState {
|
||||
public static final Key<SpreadState> SPREAD_STATE = Key.create("Spread state");
|
||||
|
||||
private final PsiType containerType;
|
||||
@Nullable private final SpreadState innerState;
|
||||
|
||||
public SpreadState(PsiType type, @Nullable SpreadState state) {
|
||||
containerType = type;
|
||||
innerState = state;
|
||||
}
|
||||
|
||||
public PsiType getContainerType() {
|
||||
return containerType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SpreadState getInnerState() {
|
||||
return innerState;
|
||||
}
|
||||
|
||||
public static SpreadState create(PsiType type, @Nullable SpreadState state) {
|
||||
return new SpreadState(type, state);
|
||||
}
|
||||
|
||||
public static PsiType apply(PsiType item, @Nullable SpreadState state, Project project) {
|
||||
if (state == null) return item;
|
||||
return apply(TypesUtil.createSimilarCollection(state.getContainerType(), project, item), state.getInnerState(), project);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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 org.jetbrains.plugins.groovy.lang.psi.impl;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClassType;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
|
||||
|
||||
/**
|
||||
* @author Max Medvedev
|
||||
*/
|
||||
public class GrSpreadType extends GrLiteralClassType {
|
||||
|
||||
private PsiType myType;
|
||||
|
||||
public GrSpreadType(PsiType original, PsiType containerType, GlobalSearchScope scope) {
|
||||
this(original, containerType, LanguageLevel.JDK_1_5, scope, JavaPsiFacade.getInstance(scope.getProject()));
|
||||
}
|
||||
|
||||
public GrSpreadType(PsiType original, PsiType containerType, LanguageLevel languageLevel, GlobalSearchScope scope, JavaPsiFacade facade) {
|
||||
super(languageLevel, scope, facade);
|
||||
|
||||
final Project project = facade.getProject();
|
||||
myType = TypesUtil.createSimilarCollection(containerType, project, original);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getJavaClassName() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiType[] getParameters() {
|
||||
return new PsiType[0]; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClassType setLanguageLevel(@NotNull LanguageLevel languageLevel) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInternalCanonicalText() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
+24
-12
@@ -16,10 +16,12 @@
|
||||
package org.jetbrains.plugins.groovy.lang.psi.impl;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor;
|
||||
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.SpreadState;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
@@ -31,28 +33,30 @@ public class GroovyResolveResultImpl implements GroovyResolveResult {
|
||||
private final PsiSubstitutor mySubstitutor;
|
||||
private final boolean myIsInvokedOnProperty;
|
||||
|
||||
private GroovyPsiElement myCurrentFileResolveContext;
|
||||
private final GroovyPsiElement myCurrentFileResolveContext;
|
||||
private final SpreadState mySpreadState;
|
||||
|
||||
public GroovyResolveResultImpl(PsiElement element, boolean isAccessible) {
|
||||
this(element, null, PsiSubstitutor.EMPTY, isAccessible, true);
|
||||
public GroovyResolveResultImpl(@NotNull PsiElement element, boolean isAccessible) {
|
||||
this(element, null, null, PsiSubstitutor.EMPTY, isAccessible, true, false);
|
||||
}
|
||||
|
||||
public GroovyResolveResultImpl(PsiElement element,
|
||||
@Nullable GroovyPsiElement context,
|
||||
PsiSubstitutor substitutor,
|
||||
public GroovyResolveResultImpl(@NotNull PsiElement element,
|
||||
@Nullable GroovyPsiElement resolveContext,
|
||||
@Nullable SpreadState spreadState,
|
||||
@NotNull PsiSubstitutor substitutor,
|
||||
boolean isAccessible,
|
||||
boolean staticsOK) {
|
||||
this(element, context, substitutor, isAccessible, staticsOK, false);
|
||||
this(element, resolveContext, spreadState, substitutor, isAccessible, staticsOK, false);
|
||||
}
|
||||
|
||||
public GroovyResolveResultImpl(PsiClassType.ClassResolveResult classResolveResult) {
|
||||
this(classResolveResult.getElement(), null, classResolveResult.getSubstitutor(), classResolveResult.isAccessible(),
|
||||
classResolveResult.isStaticsScopeCorrect());
|
||||
this(classResolveResult.getElement(), null, null, classResolveResult.getSubstitutor(), classResolveResult.isAccessible(), classResolveResult.isStaticsScopeCorrect(), false);
|
||||
}
|
||||
|
||||
public GroovyResolveResultImpl(PsiElement element,
|
||||
GroovyPsiElement resolveContext,
|
||||
PsiSubstitutor substitutor,
|
||||
public GroovyResolveResultImpl(@NotNull PsiElement element,
|
||||
@Nullable GroovyPsiElement resolveContext,
|
||||
@Nullable SpreadState spreadState,
|
||||
@NotNull PsiSubstitutor substitutor,
|
||||
boolean isAccessible,
|
||||
boolean staticsOK,
|
||||
boolean isInvokedOnProperty) {
|
||||
@@ -62,8 +66,10 @@ public class GroovyResolveResultImpl implements GroovyResolveResult {
|
||||
mySubstitutor = substitutor;
|
||||
myIsStaticsOK = staticsOK;
|
||||
myIsInvokedOnProperty = isInvokedOnProperty;
|
||||
mySpreadState = spreadState;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor getSubstitutor() {
|
||||
return mySubstitutor;
|
||||
}
|
||||
@@ -108,6 +114,7 @@ public class GroovyResolveResultImpl implements GroovyResolveResult {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GroovyPsiElement getCurrentFileResolveContext() {
|
||||
return myCurrentFileResolveContext;
|
||||
}
|
||||
@@ -116,6 +123,11 @@ public class GroovyResolveResultImpl implements GroovyResolveResult {
|
||||
return myIsInvokedOnProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpreadState getSpreadState() {
|
||||
return mySpreadState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GroovyResolveResultImpl{" +
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ public class GrConstructorInvocationImpl extends GrCallImpl implements GrConstru
|
||||
}
|
||||
|
||||
public GroovyResolveResult[] multiResolveClass() {
|
||||
return new GroovyResolveResult[]{new GroovyResolveResultImpl(getDelegatedClass(), this, PsiSubstitutor.EMPTY, true, true)};
|
||||
return new GroovyResolveResult[]{new GroovyResolveResultImpl(getDelegatedClass(), this, null, PsiSubstitutor.EMPTY, true, true)};
|
||||
}
|
||||
|
||||
public PsiMethod resolveMethod() {
|
||||
|
||||
+7
-5
@@ -35,6 +35,7 @@ import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
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.SpreadState;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
@@ -117,7 +118,7 @@ public class CompleteReferenceExpression {
|
||||
getVariantsFromQualifierForSpreadOperator(refExpr, processor, qualifier);
|
||||
}
|
||||
}
|
||||
ResolveUtil.processCategoryMembers(refExpr, processor);
|
||||
ResolveUtil.processCategoryMembers(refExpr, processor, ResolveState.initial());
|
||||
}
|
||||
|
||||
private static void getVariantsFromQualifierForSpreadOperator(GrReferenceExpression refExpr,
|
||||
@@ -206,8 +207,8 @@ public class CompleteReferenceExpression {
|
||||
|
||||
final GrPropertyForCompletion field = new GrPropertyForCompletion(method, name, type);
|
||||
if (resolveResult != null) {
|
||||
return new GroovyResolveResultImpl(field, resolveResult.getCurrentFileResolveContext(), resolveResult.getSubstitutor(),
|
||||
resolveResult.isAccessible(), resolveResult.isStaticsOK());
|
||||
return new GroovyResolveResultImpl(field, resolveResult.getCurrentFileResolveContext(), resolveResult.getSpreadState(),
|
||||
resolveResult.getSubstitutor(), resolveResult.isAccessible(), resolveResult.isStaticsOK(), false);
|
||||
}
|
||||
else {
|
||||
return new GroovyResolveResultImpl(field, true);
|
||||
@@ -377,12 +378,13 @@ public class CompleteReferenceExpression {
|
||||
|
||||
boolean isAccessible = isAccessible(namedElement);
|
||||
final GroovyPsiElement resolveContext = state.get(RESOLVE_CONTEXT);
|
||||
final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
|
||||
boolean isStaticsOK = isStaticsOK(namedElement, resolveContext, myParameters.getInvocationCount() <= 1);
|
||||
|
||||
PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY);
|
||||
if (substitutor == null) substitutor = PsiSubstitutor.EMPTY;
|
||||
|
||||
consume(new GroovyResolveResultImpl(namedElement, resolveContext, substitutor, isAccessible, isStaticsOK));
|
||||
consume(new GroovyResolveResultImpl(namedElement, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -407,7 +409,7 @@ public class CompleteReferenceExpression {
|
||||
element = ((GrReflectedMethod)element).getBaseMethod();
|
||||
if (!myProcessedMethodWithOptionalParams.add((GrMethod)element)) return;
|
||||
|
||||
result = new GroovyResolveResultImpl(element, result.getCurrentFileResolveContext(),
|
||||
result = new GroovyResolveResultImpl(element, result.getCurrentFileResolveContext(), result.getSpreadState(),
|
||||
result.getSubstitutor(), result.isAccessible(), result.isStaticsOK(),
|
||||
result.isInvokedOnProperty());
|
||||
}
|
||||
|
||||
+107
-84
@@ -42,6 +42,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
@@ -64,7 +65,8 @@ import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*;
|
||||
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mAT;
|
||||
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mMEMBER_POINTER;
|
||||
|
||||
/**
|
||||
* @author ilyas
|
||||
@@ -121,7 +123,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
if (!InheritanceUtil.isInheritor(containingClass, CommonClassNames.JAVA_UTIL_MAP)) continue;
|
||||
final String name = containingClass.getQualifiedName();
|
||||
if (name != null && name.startsWith("java.")) continue;
|
||||
if (containingClass.getLanguage() != GroovyFileType.GROOVY_LANGUAGE && !InheritanceUtil.isInheritor(containingClass, GroovyCommonClassNames.DEFAULT_BASE_CLASS_NAME)) {
|
||||
if (containingClass.getLanguage() != GroovyFileType.GROOVY_LANGUAGE &&
|
||||
!InheritanceUtil.isInheritor(containingClass, GroovyCommonClassNames.DEFAULT_BASE_CLASS_NAME)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -174,7 +177,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
String[] accessorNames = isLValue ? GroovyPropertyUtils.suggestSettersName(name) : GroovyPropertyUtils.suggestGettersName(name);
|
||||
List<GroovyResolveResult> accessorResults = new ArrayList<GroovyResolveResult>();
|
||||
for (String accessorName : accessorNames) {
|
||||
AccessorResolverProcessor accessorResolver = new AccessorResolverProcessor(accessorName, name, this, !isLValue, false, getThisType(), getTypeArguments());
|
||||
AccessorResolverProcessor accessorResolver =
|
||||
new AccessorResolverProcessor(accessorName, name, this, !isLValue, false, getThisType(), getTypeArguments());
|
||||
GrReferenceResolveUtil.resolveImpl(accessorResolver, this);
|
||||
final GroovyResolveResult[] candidates = accessorResolver.getCandidates();
|
||||
|
||||
@@ -198,7 +202,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
}
|
||||
|
||||
|
||||
|
||||
public GroovyResolveResult[] getCallVariants(GrExpression upToArgument) {
|
||||
return resolveMethodOrProperty(true, upToArgument, true);
|
||||
}
|
||||
@@ -221,13 +224,12 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* priority: inside class C: local variable, c.method, c.property, c.getter
|
||||
* in other places: local variable, c.method, c.getter, c.property
|
||||
* in other places: local variable, c.method, c.getter, c.property
|
||||
*/
|
||||
private GroovyResolveResult[] resolveMethodOrProperty(boolean allVariants, @Nullable GrExpression upToArgument, boolean genericsMatter) {
|
||||
final String name = getReferenceName();
|
||||
@@ -260,7 +262,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
for (GroovyResolveResult result : shapeResults.second) {
|
||||
final ResolveState state = ResolveState.initial().
|
||||
put(PsiSubstitutor.KEY, result.getSubstitutor()).
|
||||
put(ResolverProcessor.RESOLVE_CONTEXT, result.getCurrentFileResolveContext());
|
||||
put(ResolverProcessor.RESOLVE_CONTEXT, result.getCurrentFileResolveContext()).
|
||||
put(SpreadState.SPREAD_STATE, result.getSpreadState());
|
||||
methodResolver.execute(result.getElement(), state);
|
||||
}
|
||||
|
||||
@@ -286,7 +289,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
|
||||
//search for getters
|
||||
for (String getterName : GroovyPropertyUtils.suggestGettersName(name)) {
|
||||
AccessorResolverProcessor getterResolver = new AccessorResolverProcessor(getterName, name, this, true, genericsMatter, getThisType(), getTypeArguments());
|
||||
AccessorResolverProcessor getterResolver =
|
||||
new AccessorResolverProcessor(getterName, name, this, true, genericsMatter, getThisType(), getTypeArguments());
|
||||
GrReferenceResolveUtil.resolveImpl(getterResolver, this);
|
||||
final GroovyResolveResult[] candidates = getterResolver.getCandidates(); //can be only one candidate
|
||||
if (!allVariants && candidates.length == 1) {
|
||||
@@ -308,12 +312,13 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
|
||||
assert upToArgument == null;
|
||||
|
||||
return CachedValuesManager.getManager(getProject()).getCachedValue(this, new CachedValueProvider<Pair<Boolean, GroovyResolveResult[]>>() {
|
||||
@Override
|
||||
public Result<Pair<Boolean, GroovyResolveResult[]>> compute() {
|
||||
return Result.create(doResolveByShape(false, null), PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
});
|
||||
return CachedValuesManager.getManager(getProject())
|
||||
.getCachedValue(this, new CachedValueProvider<Pair<Boolean, GroovyResolveResult[]>>() {
|
||||
@Override
|
||||
public Result<Pair<Boolean, GroovyResolveResult[]>> compute() {
|
||||
return Result.create(doResolveByShape(false, null), PsiModificationTracker.MODIFICATION_COUNT);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Pair<Boolean, GroovyResolveResult[]> doResolveByShape(boolean allVariants, @Nullable GrExpression upToArgument) {
|
||||
@@ -329,7 +334,10 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
return Pair.create(shapeProcessor.hasApplicableCandidates(), candidates);
|
||||
}
|
||||
|
||||
private MethodResolverProcessor createMethodProcessor(boolean allVariants, String name, final boolean byShape, @Nullable GrExpression upToArgument) {
|
||||
private MethodResolverProcessor createMethodProcessor(boolean allVariants,
|
||||
String name,
|
||||
final boolean byShape,
|
||||
@Nullable GrExpression upToArgument) {
|
||||
final PsiType[] argTypes = PsiUtil.getArgumentTypes(this, false, upToArgument);
|
||||
if (byShape && argTypes != null) {
|
||||
for (int i = 0; i < argTypes.length; i++) {
|
||||
@@ -436,12 +444,13 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
return CachedValuesManager.getManager(getProject()).getCachedValue(this, new CachedValueProvider<GroovyResolveResult[]>() {
|
||||
@Override
|
||||
public Result<GroovyResolveResult[]> compute() {
|
||||
GroovyResolveResult[] value = RecursionManager.doPreventingRecursion(GrReferenceExpressionImpl.this, true, new Computable<GroovyResolveResult[]>() {
|
||||
@Override
|
||||
public GroovyResolveResult[] compute() {
|
||||
return doPolyResolve(false, false);
|
||||
}
|
||||
});
|
||||
GroovyResolveResult[] value =
|
||||
RecursionManager.doPreventingRecursion(GrReferenceExpressionImpl.this, true, new Computable<GroovyResolveResult[]>() {
|
||||
@Override
|
||||
public GroovyResolveResult[] compute() {
|
||||
return doPolyResolve(false, false);
|
||||
}
|
||||
});
|
||||
if (value == null) {
|
||||
value = GroovyResolveResult.EMPTY_ARRAY;
|
||||
}
|
||||
@@ -459,8 +468,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
private static final OurTypesCalculator TYPES_CALCULATOR = new OurTypesCalculator();
|
||||
|
||||
public PsiType getNominalType() {
|
||||
IElementType dotType = getDotTokenType();
|
||||
|
||||
final GroovyResolveResult resolveResult = advancedResolve();
|
||||
PsiElement resolved = resolveResult.getElement();
|
||||
|
||||
@@ -471,71 +478,93 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
}
|
||||
}
|
||||
|
||||
IElementType dotType = getDotTokenType();
|
||||
if (dotType == mMEMBER_POINTER) {
|
||||
return GrClosureType.create(multiResolve(false), this);
|
||||
}
|
||||
PsiType result = null;
|
||||
JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject());
|
||||
if (resolved == null && !"class".equals(getReferenceName())) {
|
||||
resolved = getReference().resolve();
|
||||
}
|
||||
if (resolved instanceof PsiClass) {
|
||||
if (getParent() instanceof GrReferenceExpression) {
|
||||
result = facade.getElementFactory().createType((PsiClass) resolved);
|
||||
} else {
|
||||
result = TypesUtil
|
||||
.createJavaLangClassType(facade.getElementFactory().createType((PsiClass)resolved), getProject(), getResolveScope());
|
||||
}
|
||||
} else if (resolved instanceof GrVariable) {
|
||||
result = ((GrVariable) resolved).getDeclaredType();
|
||||
} else if (resolved instanceof PsiVariable) {
|
||||
result = ((PsiVariable) resolved).getType();
|
||||
} else
|
||||
if (resolved instanceof PsiMethod) {
|
||||
PsiMethod method = (PsiMethod) resolved;
|
||||
if (PropertyUtil.isSimplePropertySetter(method) && !method.getName().equals(getReferenceName())) {
|
||||
result = method.getParameterList().getParameters()[0].getType();
|
||||
} else {
|
||||
PsiClass containingClass = method.getContainingClass();
|
||||
if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) &&
|
||||
"getClass".equals(method.getName())) {
|
||||
result = TypesUtil.createJavaLangClassType(getQualifierType(), getProject(), getResolveScope());
|
||||
} else {
|
||||
result = PsiUtil.getSmartReturnType(method);
|
||||
}
|
||||
|
||||
PsiType result = getNominalTypeInner(resolved);
|
||||
if (result == null) return null;
|
||||
|
||||
result = TypesUtil.substituteBoxAndNormalizeType(result, resolveResult.getSubstitutor(), resolveResult.getSpreadState(), this);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiType getNominalTypeInner(PsiElement resolved) {
|
||||
if (resolved == null && !"class".equals(getReferenceName())) {
|
||||
resolved = resolve();
|
||||
}
|
||||
|
||||
if (resolved instanceof PsiClass) {
|
||||
final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
|
||||
if (getParent() instanceof GrReferenceExpression) {
|
||||
return factory.createType((PsiClass)resolved);
|
||||
}
|
||||
} else if (resolved instanceof GrReferenceExpression) {
|
||||
else {
|
||||
return TypesUtil.createJavaLangClassType(factory.createType((PsiClass)resolved), getProject(), getResolveScope());
|
||||
}
|
||||
}
|
||||
|
||||
if (resolved instanceof GrVariable) {
|
||||
return ((GrVariable)resolved).getDeclaredType();
|
||||
}
|
||||
|
||||
if (resolved instanceof PsiVariable) {
|
||||
return ((PsiVariable)resolved).getType();
|
||||
}
|
||||
|
||||
if (resolved instanceof PsiMethod) {
|
||||
PsiMethod method = (PsiMethod)resolved;
|
||||
if (PropertyUtil.isSimplePropertySetter(method) && !method.getName().equals(getReferenceName())) {
|
||||
return method.getParameterList().getParameters()[0].getType();
|
||||
}
|
||||
|
||||
//'class' property with explicit generic
|
||||
PsiClass containingClass = method.getContainingClass();
|
||||
if (containingClass != null &&
|
||||
CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) &&
|
||||
"getClass".equals(method.getName())) {
|
||||
return TypesUtil.createJavaLangClassType(getQualifierType(), getProject(), getResolveScope());
|
||||
}
|
||||
|
||||
return PsiUtil.getSmartReturnType(method);
|
||||
}
|
||||
|
||||
if (resolved instanceof GrReferenceExpression) {
|
||||
PsiElement parent = resolved.getParent();
|
||||
if (parent instanceof GrAssignmentExpression) {
|
||||
GrAssignmentExpression assignment = (GrAssignmentExpression) parent;
|
||||
GrAssignmentExpression assignment = (GrAssignmentExpression)parent;
|
||||
if (resolved.equals(assignment.getLValue())) {
|
||||
GrExpression rValue = assignment.getRValue();
|
||||
if (rValue != null) {
|
||||
PsiType rType = rValue.getType();
|
||||
if (rType != null) result = rType;
|
||||
if (rType != null) {
|
||||
return rType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (resolved == null) {
|
||||
GrExpression qualifier = getQualifierExpression();
|
||||
|
||||
if (resolved == null) {
|
||||
if ("class".equals(getReferenceName())) {
|
||||
result = TypesUtil.createJavaLangClassType(getQualifierType(), getProject(), getResolveScope());
|
||||
return TypesUtil.createJavaLangClassType(getQualifierType(), getProject(), getResolveScope());
|
||||
}
|
||||
else {
|
||||
if (qualifier != null) {
|
||||
PsiType qType = qualifier.getType();
|
||||
if (qType instanceof PsiClassType) {
|
||||
PsiClassType.ClassResolveResult qResult = ((PsiClassType)qType).resolveGenerics();
|
||||
PsiClass clazz = qResult.getElement();
|
||||
if (clazz != null) {
|
||||
PsiClass mapClass = facade.findClass(CommonClassNames.JAVA_UTIL_MAP, getResolveScope());
|
||||
if (mapClass != null && mapClass.getTypeParameters().length == 2) {
|
||||
PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(mapClass, clazz, qResult.getSubstitutor());
|
||||
if (substitutor != null) {
|
||||
result = TypeConversionUtil.erasure(substitutor.substitute(mapClass.getTypeParameters()[1]));
|
||||
}
|
||||
|
||||
//map access
|
||||
GrExpression qualifier = getQualifierExpression();
|
||||
if (qualifier != null) {
|
||||
PsiType qType = qualifier.getType();
|
||||
if (qType instanceof PsiClassType) {
|
||||
PsiClassType.ClassResolveResult qResult = ((PsiClassType)qType).resolveGenerics();
|
||||
PsiClass clazz = qResult.getElement();
|
||||
if (clazz != null) {
|
||||
PsiClass mapClass = JavaPsiFacade.getInstance(getProject()).findClass(CommonClassNames.JAVA_UTIL_MAP, getResolveScope());
|
||||
if (mapClass != null && mapClass.getTypeParameters().length == 2) {
|
||||
PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(mapClass, clazz, qResult.getSubstitutor());
|
||||
if (substitutor != null) {
|
||||
return TypeConversionUtil.erasure(substitutor.substitute(mapClass.getTypeParameters()[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -543,14 +572,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
}
|
||||
}
|
||||
|
||||
if (result != null) {
|
||||
result = TypesUtil.substituteBoxAndNormalizeType(result, resolveResult.getSubstitutor(), this);
|
||||
}
|
||||
if (dotType != mSPREAD_DOT) {
|
||||
return result;
|
||||
} else {
|
||||
return ResolveUtil.getListTypeForSpreadOperator(this, result);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -588,7 +610,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
if (!resolved.isValid()) {
|
||||
throw new AssertionError("Invalid target of a valid reference");
|
||||
}
|
||||
return ((GrVariable) resolved).getTypeGroovy();
|
||||
return ((GrVariable)resolved).getTypeGroovy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,7 +620,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
if (nominal == null) return inferred;
|
||||
if (!TypeConversionUtil.isAssignable(nominal, inferred, false)) {
|
||||
final PsiElement resolved = refExpr.resolve();
|
||||
if (resolved instanceof GrVariable && ((GrVariable) resolved).getTypeElementGroovy() != null) {
|
||||
if (resolved instanceof GrVariable && ((GrVariable)resolved).getTypeElementGroovy() != null) {
|
||||
return nominal; //see GRVY-487
|
||||
}
|
||||
}
|
||||
@@ -650,7 +672,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
return results;
|
||||
default:
|
||||
return GroovyResolveResult.EMPTY_ARRAY;
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
private PsiType getThisType() {
|
||||
GrExpression qualifier = getQualifierExpression();
|
||||
@@ -755,13 +778,13 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
|
||||
|
||||
public GroovyResolveResult advancedResolve() {
|
||||
ResolveResult[] results = ResolveCache.getInstance(getProject()).resolveWithCaching(this, POLY_RESOLVER, true, false);
|
||||
return results.length == 1 ? (GroovyResolveResult) results[0] : GroovyResolveResult.EMPTY_RESULT;
|
||||
return results.length == 1 ? (GroovyResolveResult)results[0] : GroovyResolveResult.EMPTY_RESULT;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GroovyResolveResult[] multiResolve(boolean incomplete) { //incomplete means we do not take arguments into consideration
|
||||
final ResolveResult[] results = ResolveCache.getInstance(getProject()).resolveWithCaching(this, POLY_RESOLVER, true, incomplete);
|
||||
return results.length == 0 ? GroovyResolveResult.EMPTY_ARRAY : (GroovyResolveResult[])results;
|
||||
return results.length == 0 ? GroovyResolveResult.EMPTY_ARRAY : (GroovyResolveResult[])results;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+55
-51
@@ -18,9 +18,13 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrThisReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
|
||||
@@ -39,10 +43,11 @@ import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mSPREAD_D
|
||||
* @author Medvedev Max
|
||||
*/
|
||||
public class GrReferenceResolveUtil {
|
||||
|
||||
private GrReferenceResolveUtil() {
|
||||
}
|
||||
|
||||
public static boolean resolveImpl(ResolverProcessor processor, GrReferenceExpression place) {
|
||||
static boolean resolveImpl(ResolverProcessor processor, GrReferenceExpression place) {
|
||||
GrExpression qualifier = place.getQualifier();
|
||||
if (qualifier == null) {
|
||||
if (processor instanceof MethodResolverProcessor || processor instanceof CompletionProcessor) {
|
||||
@@ -62,7 +67,14 @@ public class GrReferenceResolveUtil {
|
||||
}
|
||||
else {
|
||||
if (place.getDotTokenType() == mSPREAD_DOT) {
|
||||
if (!processQualifierForSpreadDot(processor, qualifier, place)) return false;
|
||||
final PsiType qtype = qualifier.getType();
|
||||
final PsiType componentType = getComponentTypeForSpreadDot(qtype, place);
|
||||
if (componentType != null) {
|
||||
final ResolveState state = ResolveState.initial()
|
||||
.put(ResolverProcessor.RESOLVE_CONTEXT, qualifier)
|
||||
.put(SpreadState.SPREAD_STATE, SpreadState.create(qtype, null));
|
||||
if (!processQualifierType(processor, componentType, state, place)) return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!processQualifier(processor, qualifier, place)) return false;
|
||||
@@ -88,10 +100,10 @@ public class GrReferenceResolveUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean processIfJavaLangClass(ResolverProcessor processor,
|
||||
private static boolean processIfJavaLangClass(ResolverProcessor processor,
|
||||
PsiType type,
|
||||
GroovyPsiElement resolveContext,
|
||||
GroovyPsiElement place) {
|
||||
GrReferenceExpression place) {
|
||||
if (!(type instanceof PsiClassType)) return true;
|
||||
|
||||
final PsiClass psiClass = ((PsiClassType)type).resolve();
|
||||
@@ -100,70 +112,60 @@ public class GrReferenceResolveUtil {
|
||||
final PsiType[] params = ((PsiClassType)type).getParameters();
|
||||
if (params.length != 1) return true;
|
||||
|
||||
if (!processClassQualifierType(processor, params[0], resolveContext, place)) return false;
|
||||
if (!processQualifierType(processor, params[0], ResolveState.initial().put(ResolverProcessor.RESOLVE_CONTEXT, resolveContext), place)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean processQualifierForSpreadDot(ResolverProcessor processor, GrExpression qualifier, GroovyPsiElement place) {
|
||||
PsiType qualifierType = qualifier.getType();
|
||||
|
||||
|
||||
@Nullable
|
||||
private static PsiType getComponentTypeForSpreadDot(@Nullable PsiType qualifierType, @NotNull GroovyPsiElement place) {
|
||||
if (qualifierType instanceof PsiArrayType) {
|
||||
if (!processClassQualifierType(processor, ((PsiArrayType)qualifierType).getComponentType(), qualifier, place)) return false;
|
||||
return true;
|
||||
return ((PsiArrayType)qualifierType).getComponentType();
|
||||
}
|
||||
|
||||
|
||||
//process for collections
|
||||
if (!(qualifierType instanceof PsiClassType)) return true;
|
||||
if (!(qualifierType instanceof PsiClassType)) return null;
|
||||
|
||||
PsiClassType.ClassResolveResult result = ((PsiClassType)qualifierType).resolveGenerics();
|
||||
PsiClass clazz = result.getElement();
|
||||
if (clazz == null) return true;
|
||||
if (clazz == null) return null;
|
||||
|
||||
PsiClass collection = GroovyPsiManager.getInstance(place.getProject())
|
||||
.findClassWithCache(CommonClassNames.JAVA_UTIL_COLLECTION, place.getResolveScope());
|
||||
if (collection == null || collection.getTypeParameters().length != 1) return true;
|
||||
PsiClass collection = GroovyPsiManager.getInstance(place.getProject()).findClassWithCache(CommonClassNames.JAVA_UTIL_COLLECTION,
|
||||
place.getResolveScope());
|
||||
if (collection == null || collection.getTypeParameters().length != 1) return null;
|
||||
|
||||
PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(collection, clazz, result.getSubstitutor());
|
||||
if (substitutor == null) return true;
|
||||
if (substitutor == null) return null;
|
||||
|
||||
PsiType componentType = substitutor.substitute(collection.getTypeParameters()[0]);
|
||||
if (componentType == null) return true;
|
||||
|
||||
if (!processClassQualifierType(processor, componentType, qualifier, place)) return false;
|
||||
return true;
|
||||
return substitutor.substitute(collection.getTypeParameters()[0]);
|
||||
}
|
||||
|
||||
public static boolean processQualifier(PsiScopeProcessor processor, GrExpression qualifier, GroovyPsiElement place) {
|
||||
public static boolean processQualifier(PsiScopeProcessor processor, GrExpression qualifier, GrReferenceExpression place) {
|
||||
PsiType qualifierType = qualifier.getType();
|
||||
ResolveState state = ResolveState.initial().put(ResolverProcessor.RESOLVE_CONTEXT, qualifier);
|
||||
if (qualifierType == null) {
|
||||
if (qualifier instanceof GrReferenceExpression) {
|
||||
PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
|
||||
if (resolved instanceof PsiPackage) {
|
||||
final ResolveState state = ResolveState.initial().put(ResolverProcessor.RESOLVE_CONTEXT, qualifier);
|
||||
if (!resolved.processDeclarations(processor, state, null, place)) return false;
|
||||
}
|
||||
else {
|
||||
qualifierType = TypesUtil.getJavaLangObject(place);
|
||||
if (!processClassQualifierType(processor, qualifierType, qualifier, place)) return false;
|
||||
if (!processQualifierType(processor, qualifierType, state, place)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (qualifierType instanceof PsiIntersectionType) {
|
||||
for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) {
|
||||
if (!processClassQualifierType(processor, conjunct, qualifier, place)) return false;
|
||||
if (!processQualifierType(processor, conjunct, state, place)) return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!processClassQualifierType(processor, qualifierType, qualifier, place)) return false;
|
||||
if (!processQualifierType(processor, qualifierType, state, place)) return false;
|
||||
if (qualifier instanceof GrReferenceExpression) {
|
||||
PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
|
||||
if (resolved instanceof PsiClass) { //omitted .class
|
||||
PsiClass javaLangClass = PsiUtil.getJavaLangClass(resolved, place.getResolveScope());
|
||||
if (javaLangClass != null) {
|
||||
ResolveState state = ResolveState.initial();
|
||||
PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters();
|
||||
PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY);
|
||||
if (substitutor == null) substitutor = PsiSubstitutor.EMPTY;
|
||||
@@ -172,8 +174,7 @@ public class GrReferenceResolveUtil {
|
||||
state = state.put(PsiSubstitutor.KEY, substitutor);
|
||||
}
|
||||
if (!javaLangClass.processDeclarations(processor, state, null, place)) return false;
|
||||
PsiType javaLangClassType =
|
||||
JavaPsiFacade.getInstance(place.getProject()).getElementFactory().createType(javaLangClass, substitutor);
|
||||
PsiType javaLangClassType = TypesUtil.createJavaLangClassType(qualifierType, place.getProject(), place.getResolveScope());
|
||||
if (!ResolveUtil.processNonCodeMembers(javaLangClassType, processor, place, state)) return false;
|
||||
}
|
||||
}
|
||||
@@ -183,39 +184,42 @@ public class GrReferenceResolveUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean processClassQualifierType(PsiScopeProcessor processor,
|
||||
PsiType qualifierType,
|
||||
GroovyPsiElement resolveContext,
|
||||
GroovyPsiElement place) {
|
||||
final ResolveState state;
|
||||
if (qualifierType instanceof PsiDisjunctionType) {
|
||||
qualifierType = ((PsiDisjunctionType)qualifierType).getLeastUpperBound();
|
||||
private static boolean processQualifierType(final PsiScopeProcessor processor,
|
||||
final PsiType originalQualifierType,
|
||||
final ResolveState state,
|
||||
final GrReferenceExpression place) {
|
||||
PsiType qualifierType = originalQualifierType instanceof PsiDisjunctionType
|
||||
? ((PsiDisjunctionType)originalQualifierType).getLeastUpperBound()
|
||||
: originalQualifierType;
|
||||
|
||||
if (qualifierType instanceof PsiIntersectionType) {
|
||||
for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) {
|
||||
if (!processQualifierType(processor, conjunct, state, place)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (qualifierType instanceof PsiClassType) {
|
||||
PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType)qualifierType).resolveGenerics();
|
||||
PsiClass qualifierClass = qualifierResult.getElement();
|
||||
state = ResolveState.initial().put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor())
|
||||
.put(ResolverProcessor.RESOLVE_CONTEXT, resolveContext);
|
||||
if (qualifierClass != null) {
|
||||
if (!qualifierClass.processDeclarations(processor, state, null, place)) return false;
|
||||
if (!qualifierClass.processDeclarations(processor, state.put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, place)) return false;
|
||||
}
|
||||
}
|
||||
else if (qualifierType instanceof PsiArrayType) {
|
||||
final GrTypeDefinition arrayClass = GroovyPsiManager.getInstance(place.getProject()).getArrayClass();
|
||||
state = ResolveState.initial();
|
||||
if (!arrayClass.processDeclarations(processor, state, null, place)) return false;
|
||||
}
|
||||
else if (qualifierType instanceof PsiIntersectionType) {
|
||||
for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) {
|
||||
if (!processClassQualifierType(processor, conjunct, resolveContext, place)) return false;
|
||||
|
||||
if (!(place.getParent() instanceof GrMethodCall)) {
|
||||
final PsiType componentType = getComponentTypeForSpreadDot(qualifierType, place);
|
||||
if (componentType != null) {
|
||||
final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
|
||||
processQualifierType(processor, componentType, state.put(SpreadState.SPREAD_STATE, SpreadState.create(qualifierType, spreadState)), place);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
state = ResolveState.initial();
|
||||
}
|
||||
|
||||
if (!ResolveUtil.processCategoryMembers(place, processor)) return false;
|
||||
if (!ResolveUtil.processCategoryMembers(place, processor, state)) return false;
|
||||
if (!ResolveUtil.processNonCodeMembers(qualifierType, processor, place, state)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
+49
-2
@@ -35,6 +35,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrTypeConverter;
|
||||
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.SpreadState;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignature;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression;
|
||||
@@ -688,14 +689,16 @@ public class TypesUtil {
|
||||
@Nullable
|
||||
public static PsiType substituteBoxAndNormalizeType(@Nullable PsiType type,
|
||||
@NotNull PsiSubstitutor substitutor,
|
||||
@NotNull GrExpression expression) {
|
||||
@Nullable SpreadState state, @NotNull GrExpression expression) {
|
||||
if (type == null) return null;
|
||||
GlobalSearchScope resolveScope = expression.getResolveScope();
|
||||
PsiManager manager = expression.getManager();
|
||||
type = substitutor.substitute(type);
|
||||
type = boxPrimitiveType(type, manager, resolveScope);
|
||||
if (type == null) return null;
|
||||
return PsiImplUtil.normalizeWildcardTypeByPosition(type, expression);
|
||||
type = PsiImplUtil.normalizeWildcardTypeByPosition(type, expression);
|
||||
type = SpreadState.apply(type, state, expression.getProject());
|
||||
return type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -705,4 +708,48 @@ public class TypesUtil {
|
||||
if (containerType instanceof PsiArrayType) return ((PsiArrayType)containerType).getComponentType();
|
||||
return PsiUtil.extractIterableTypeParameter(containerType, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiClassType createSimilarCollection(PsiType collection, Project project, PsiType... itemType) {
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.SortedSet")) {
|
||||
return createCollection(project, "java.util.SortedSet", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.LinkedHashSet")) {
|
||||
return createCollection(project, "java.util.LinkedHashSet", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.Set")) {
|
||||
return createCollection(project, "java.util.HashSet", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.LinkedList")) {
|
||||
return createCollection(project, "java.util.LInkedList", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.Stack")) {
|
||||
return createCollection(project, "java.util.Stack", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.Vector")) {
|
||||
return createCollection(project, "java.util.Vector", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.List")) {
|
||||
return createCollection(project, "java.util.ArrayList", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.Queue")) {
|
||||
return createCollection(project, "java.util.LinkedList", itemType);
|
||||
}
|
||||
|
||||
return createCollection(project, "java.util.ArrayList", itemType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiClassType createCollection(Project project, String collectionName, PsiType... item) {
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
PsiClass collection =
|
||||
JavaPsiFacade.getInstance(project).findClass(collectionName, GlobalSearchScope.allScope(project));
|
||||
if (collection == null) return null;
|
||||
|
||||
PsiTypeParameter[] parameters = collection.getTypeParameters();
|
||||
if (parameters.length != 1) return null;
|
||||
|
||||
return factory.createType(collection, item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+36
-29
@@ -21,7 +21,6 @@ import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.hash.HashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
|
||||
@@ -54,48 +53,56 @@ public class DefaultCallExpressionTypeCalculator extends GrCallExpressionTypeCal
|
||||
PsiManager manager = callExpression.getManager();
|
||||
PsiType result = null;
|
||||
for (GroovyResolveResult resolveResult : resolveResults) {
|
||||
PsiElement resolved = resolveResult.getElement();
|
||||
PsiType returnType = null;
|
||||
if (resolved instanceof PsiMethod) {
|
||||
PsiMethod method = (PsiMethod) resolved;
|
||||
if (resolveResult.isInvokedOnProperty()) {
|
||||
final PsiType propertyType = PsiUtil.getSmartReturnType(method);
|
||||
returnType = extractReturnTypeFromType(propertyType, true, callExpression);
|
||||
} else {
|
||||
returnType = getClosureMethodsReturnType(callExpression, refExpr, method);
|
||||
if (returnType == null) {
|
||||
returnType = PsiUtil.getSmartReturnType(method);
|
||||
}
|
||||
}
|
||||
} else if (resolved instanceof GrVariable) {
|
||||
PsiType refType = refExpr.getType();
|
||||
final PsiType type = refType == null ? ((GrVariable) resolved).getTypeGroovy() : refType;
|
||||
returnType = extractReturnTypeFromType(type, false, callExpression);
|
||||
}
|
||||
PsiType returnType = calculateReturnTypeInner(callExpression, refExpr, resolveResult);
|
||||
|
||||
if (returnType == null) return null;
|
||||
if (!(returnType instanceof GrLiteralClassType)) {
|
||||
returnType = TypesUtil.substituteBoxAndNormalizeType(returnType, resolveResult.getSubstitutor(), callExpression);
|
||||
returnType = TypesUtil.substituteBoxAndNormalizeType(returnType, resolveResult.getSubstitutor(), resolveResult.getSpreadState(), callExpression);
|
||||
LOG.assertTrue(returnType != null);
|
||||
}
|
||||
|
||||
if (result == null || returnType.isAssignableFrom(result)) result = returnType;
|
||||
else if (!result.isAssignableFrom(returnType))
|
||||
if (result == null || returnType.isAssignableFrom(result)) {
|
||||
result = returnType;
|
||||
}
|
||||
else if (!result.isAssignableFrom(returnType)) {
|
||||
result = TypesUtil.getLeastUpperBound(result, returnType, manager);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) return null;
|
||||
|
||||
if (refExpr.getDotTokenType() != GroovyTokenTypes.mSPREAD_DOT) {
|
||||
return result;
|
||||
} else {
|
||||
return ResolveUtil.getListTypeForSpreadOperator(refExpr, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return extractReturnTypeFromType(invoked.getType(), false, callExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiType calculateReturnTypeInner(GrMethodCall callExpression,
|
||||
GrReferenceExpression refExpr,
|
||||
GroovyResolveResult resolveResult) {
|
||||
PsiElement resolved = resolveResult.getElement();
|
||||
PsiType returnType = null;
|
||||
if (resolved instanceof PsiMethod) {
|
||||
PsiMethod method = (PsiMethod)resolved;
|
||||
if (resolveResult.isInvokedOnProperty()) {
|
||||
final PsiType propertyType = PsiUtil.getSmartReturnType(method);
|
||||
returnType = extractReturnTypeFromType(propertyType, true, callExpression);
|
||||
}
|
||||
else {
|
||||
returnType = getClosureMethodsReturnType(callExpression, refExpr, method);
|
||||
if (returnType == null) {
|
||||
returnType = PsiUtil.getSmartReturnType(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (resolved instanceof GrVariable) {
|
||||
PsiType refType = refExpr.getType();
|
||||
final PsiType type = refType == null ? ((GrVariable)resolved).getTypeGroovy() : refType;
|
||||
returnType = extractReturnTypeFromType(type, false, callExpression);
|
||||
}
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiType extractReturnTypeFromType(PsiType type, boolean returnTypeIfFail, GrMethodCall callExpression) {
|
||||
PsiType returnType = returnTypeIfFail ? type: null;
|
||||
|
||||
+2
-47
@@ -15,10 +15,7 @@
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.containers.hash.HashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -28,6 +25,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethod
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.GrCallExpressionTypeCalculator;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
|
||||
|
||||
@@ -82,7 +80,7 @@ public class GrDGMTypeCalculator extends GrCallExpressionTypeCalculator {
|
||||
itemType = iitype;
|
||||
}
|
||||
}
|
||||
return createSimilarCollection(type, callExpression.getProject(), itemType);
|
||||
return TypesUtil.createSimilarCollection(type, callExpression.getProject(), itemType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,49 +98,6 @@ public class GrDGMTypeCalculator extends GrCallExpressionTypeCalculator {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiType createSimilarCollection(PsiType collection, Project project, PsiType... itemType) {
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.SortedSet")) {
|
||||
return createCollection(project, "java.util.SortedSet", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.LinkedHashSet")) {
|
||||
return createCollection(project, "java.util.LinkedHashSet", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.Set")) {
|
||||
return createCollection(project, "java.util.HashSet", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.LinkedList")) {
|
||||
return createCollection(project, "java.util.LInkedList", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.Stack")) {
|
||||
return createCollection(project, "java.util.Stack", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.Vector")) {
|
||||
return createCollection(project, "java.util.Vector", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.List")) {
|
||||
return createCollection(project, "java.util.ArrayList", itemType);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(collection, "java.util.Queue")) {
|
||||
return createCollection(project, "java.util.LinkedList", itemType);
|
||||
}
|
||||
|
||||
return createCollection(project, "java.util.ArrayList", itemType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiType createCollection(Project project, String collectionName, PsiType... item) {
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
PsiClass collection =
|
||||
JavaPsiFacade.getInstance(project).findClass(collectionName, GlobalSearchScope.allScope(project));
|
||||
if (collection == null) return null;
|
||||
|
||||
PsiTypeParameter[] parameters = collection.getTypeParameters();
|
||||
if (parameters.length != 1) return null;
|
||||
|
||||
return factory.createType(collection, item);
|
||||
}
|
||||
|
||||
private static boolean isSimilarCollectionReturner(PsiMethod resolved) {
|
||||
PsiParameter[] params = resolved.getParameterList().getParameters();
|
||||
if (params.length == 0) return false;
|
||||
|
||||
+1
-1
@@ -270,7 +270,7 @@ public class GrIndexPropertyImpl extends GrExpressionImpl implements GrIndexProp
|
||||
PsiParameter[] parameters = ((PsiMethod)element).getParameterList().getParameters();
|
||||
if (parameters.length > 1) {
|
||||
PsiParameter last = parameters[parameters.length - 1];
|
||||
return TypesUtil.substituteBoxAndNormalizeType(last.getType(), candidate.getSubstitutor(), this);
|
||||
return TypesUtil.substituteBoxAndNormalizeType(last.getType(), candidate.getSubstitutor(), candidate.getSpreadState(), this);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
+1
-3
@@ -102,8 +102,7 @@ public class GrEnumConstantImpl extends GrFieldImpl implements GrEnumConstant {
|
||||
}
|
||||
|
||||
public GroovyResolveResult[] multiResolveClass() {
|
||||
final PsiClass psiClass = getContainingClass();
|
||||
GroovyResolveResult result = new GroovyResolveResultImpl(psiClass, this, PsiSubstitutor.EMPTY, true, true);
|
||||
GroovyResolveResult result = new GroovyResolveResultImpl(getContainingClass(), this, null, PsiSubstitutor.EMPTY, true, true);
|
||||
return new GroovyResolveResult[]{result};
|
||||
}
|
||||
|
||||
@@ -135,7 +134,6 @@ public class GrEnumConstantImpl extends GrFieldImpl implements GrEnumConstant {
|
||||
public GrExpression[] getExpressionArguments() {
|
||||
final GrArgumentList argumentList = getArgumentList();
|
||||
return argumentList == null ? GrExpression.EMPTY_ARRAY : argumentList.getExpressionArguments();
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+1
-1
@@ -376,7 +376,7 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl<GrCodeRef
|
||||
final PsiSubstitutor substitutor = result.getSubstitutor();
|
||||
final PsiSubstitutor newSubstitutor = substitutor.putAll((PsiClass) element, args);
|
||||
GroovyPsiElement context = result.getCurrentFileResolveContext();
|
||||
GroovyResolveResultImpl newResult = new GroovyResolveResultImpl(element, context, newSubstitutor, result.isAccessible(), result.isStaticsOK());
|
||||
GroovyResolveResultImpl newResult = new GroovyResolveResultImpl(element, context, null, newSubstitutor, result.isAccessible(), result.isStaticsOK());
|
||||
results[i] = newResult;
|
||||
if (context instanceof GrImportStatement) {
|
||||
imported.add(newResult);
|
||||
|
||||
@@ -62,7 +62,7 @@ public class GdkMethodUtil {
|
||||
private GdkMethodUtil() {
|
||||
}
|
||||
|
||||
public static boolean categoryIteration(GrClosableBlock place, final PsiScopeProcessor processor) {
|
||||
public static boolean categoryIteration(GrClosableBlock place, final PsiScopeProcessor processor, ResolveState state) {
|
||||
final ClassHint classHint = processor.getHint(ClassHint.KEY);
|
||||
if (classHint != null && !classHint.shouldProcess(ClassHint.ResolveKind.METHOD)) return true;
|
||||
|
||||
@@ -79,11 +79,12 @@ public class GdkMethodUtil {
|
||||
|
||||
if (!(call.resolveMethod() instanceof GrGdkMethod)) return true;
|
||||
|
||||
state = state.put(ResolverProcessor.RESOLVE_CONTEXT, call);
|
||||
for (GrExpression arg : args) {
|
||||
if (arg instanceof GrReferenceExpression) {
|
||||
final PsiElement resolved = ((GrReferenceExpression)arg).resolve();
|
||||
if (resolved instanceof PsiClass) {
|
||||
if (!processCategoryMethods(place, processor, call, (PsiClass)resolved)) return false;
|
||||
if (!processCategoryMethods(place, processor, state, (PsiClass)resolved)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +101,7 @@ public class GdkMethodUtil {
|
||||
*/
|
||||
public static boolean processCategoryMethods(final GroovyPsiElement place,
|
||||
final PsiScopeProcessor processor,
|
||||
@Nullable GroovyPsiElement resolveContext,
|
||||
@NotNull ResolveState state,
|
||||
@NotNull PsiClass categoryClass) {
|
||||
final DelegatingScopeProcessor delegate = new DelegatingScopeProcessor(processor) {
|
||||
@Override
|
||||
@@ -114,18 +115,17 @@ public class GdkMethodUtil {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
final ResolveState state = ResolveState.initial().put(ResolverProcessor.RESOLVE_CONTEXT, resolveContext);
|
||||
return categoryClass.processDeclarations(delegate, state, null, place);
|
||||
}
|
||||
|
||||
public static boolean withIteration(GrClosableBlock block, final PsiScopeProcessor processor, GroovyPsiElement place) {
|
||||
public static boolean withIteration(GrClosableBlock block, final PsiScopeProcessor processor) {
|
||||
GrMethodCall call = checkMethodCall(block, WITH);
|
||||
if (call == null) return true;
|
||||
final GrExpression invoked = call.getInvokedExpression();
|
||||
LOG.assertTrue(invoked instanceof GrReferenceExpression);
|
||||
final GrExpression qualifier = ((GrReferenceExpression)invoked).getQualifier();
|
||||
if (qualifier == null) return true;
|
||||
if (!GrReferenceResolveUtil.processQualifier(processor, qualifier, place)) return false;
|
||||
if (!GrReferenceResolveUtil.processQualifier(processor, qualifier, (GrReferenceExpression)invoked)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -937,7 +937,7 @@ public class PsiUtil {
|
||||
|
||||
final GroovyResolveResult grResult = resolveResult instanceof GroovyResolveResult
|
||||
? (GroovyResolveResult)resolveResult
|
||||
: new GroovyResolveResultImpl(psiClass, context, substitutor, true, true);
|
||||
: new GroovyResolveResultImpl(psiClass, context, null, substitutor, true, true);
|
||||
return getConstructorCandidates(context, new GroovyResolveResult[]{grResult}, argTypes);
|
||||
}
|
||||
|
||||
|
||||
@@ -101,20 +101,20 @@ public class ResolveUtil {
|
||||
}
|
||||
if (doProcessNonCodeMembers) {
|
||||
if (run instanceof GrTypeDefinition) {
|
||||
if (!processNonCodeMembers(factory.createType(((GrTypeDefinition)run)), processor, place)) return false;
|
||||
if (!processNonCodeMembers(factory.createType(((GrTypeDefinition)run)), processor, place, ResolveState.initial())) return false;
|
||||
}
|
||||
else if ((run instanceof GroovyFileBase) && ((GroovyFileBase)run).isScript()) {
|
||||
final PsiClass psiClass = ((GroovyFileBase)run).getScriptClass();
|
||||
if (psiClass != null) {
|
||||
if (!processNonCodeMembers(factory.createType(psiClass), processor, place)) return false;
|
||||
if (!processNonCodeMembers(factory.createType(psiClass), processor, place, ResolveState.initial())) return false;
|
||||
}
|
||||
}
|
||||
else if (run instanceof GrClosableBlock) {
|
||||
PsiClass superClass = getLiteralSuperClass((GrClosableBlock)run);
|
||||
if (superClass != null && !superClass.processDeclarations(processor, ResolveState.initial(), null, place)) return false;
|
||||
|
||||
if (!GdkMethodUtil.categoryIteration((GrClosableBlock)run, processor)) return false;
|
||||
if (!GdkMethodUtil.withIteration((GrClosableBlock)run, processor, place)) return false;
|
||||
if (!GdkMethodUtil.categoryIteration((GrClosableBlock)run, processor, ResolveState.initial())) return false;
|
||||
if (!GdkMethodUtil.withIteration((GrClosableBlock)run, processor)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,12 +128,12 @@ public class ResolveUtil {
|
||||
|
||||
public static boolean processChildren(PsiElement element,
|
||||
PsiScopeProcessor processor,
|
||||
ResolveState substitutor,
|
||||
ResolveState state,
|
||||
PsiElement lastParent,
|
||||
PsiElement place) {
|
||||
PsiElement run = lastParent == null ? element.getLastChild() : lastParent.getPrevSibling();
|
||||
while (run != null) {
|
||||
if (!run.processDeclarations(processor, substitutor, null, place)) return false;
|
||||
if (!run.processDeclarations(processor, state, null, place)) return false;
|
||||
run = run.getPrevSibling();
|
||||
}
|
||||
|
||||
@@ -175,16 +175,10 @@ public class ResolveUtil {
|
||||
}
|
||||
}
|
||||
if (!processNonCodeMembers(type, processor, place, state)) return false;
|
||||
if (!processCategoryMembers(place, processor)) return false;
|
||||
if (!processCategoryMembers(place, processor, state)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean processNonCodeMembers(PsiType type,
|
||||
PsiScopeProcessor processor,
|
||||
GroovyPsiElement place) {
|
||||
return processNonCodeMembers(type, processor, place, ResolveState.initial());
|
||||
}
|
||||
|
||||
public static boolean processNonCodeMembers(PsiType type,
|
||||
PsiScopeProcessor processor,
|
||||
GroovyPsiElement place,
|
||||
@@ -277,21 +271,6 @@ public class ResolveUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiType getListTypeForSpreadOperator(GrReferenceExpression refExpr, PsiType componentType) {
|
||||
PsiClass clazz = JavaPsiFacade.getInstance(refExpr.getManager().getProject())
|
||||
.findClass(CommonClassNames.JAVA_UTIL_LIST, refExpr.getResolveScope());
|
||||
if (clazz != null) {
|
||||
PsiTypeParameter[] typeParameters = clazz.getTypeParameters();
|
||||
if (typeParameters.length == 1) {
|
||||
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY.put(typeParameters[0], componentType);
|
||||
return JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory().createType(clazz, substitutor);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static GroovyPsiElement resolveProperty(GroovyPsiElement place, String name) {
|
||||
PropertyResolverProcessor processor = new PropertyResolverProcessor(name, place);
|
||||
return resolveExistingElement(place, processor, GrVariable.class, GrReferenceExpression.class);
|
||||
@@ -384,9 +363,9 @@ public class ResolveUtil {
|
||||
return resolveLabelTargets(labelName, element, isBreak).first;
|
||||
}
|
||||
|
||||
public static boolean processCategoryMembers(GroovyPsiElement place, PsiScopeProcessor processor) {
|
||||
public static boolean processCategoryMembers(GroovyPsiElement place, PsiScopeProcessor processor, ResolveState state) {
|
||||
boolean gpp = GppTypeConverter.hasTypedContext(place);
|
||||
if (gpp && !processUseAnnotation(place, processor)) return false;
|
||||
if (gpp && !processUseAnnotation(place, processor, state)) return false;
|
||||
|
||||
boolean inCodeBlock = true;
|
||||
PsiElement run = place;
|
||||
@@ -395,14 +374,15 @@ public class ResolveUtil {
|
||||
inCodeBlock = false;
|
||||
}
|
||||
if (run instanceof GrClosableBlock) {
|
||||
if (inCodeBlock && !GdkMethodUtil.categoryIteration((GrClosableBlock)run, processor)) return false;
|
||||
if (inCodeBlock && !GdkMethodUtil.categoryIteration((GrClosableBlock)run, processor, state)) return false;
|
||||
|
||||
PsiClass superClass = getLiteralSuperClass((GrClosableBlock)run);
|
||||
if (superClass != null && !GdkMethodUtil.processCategoryMethods(((GrClosableBlock)run), processor, null, superClass)) return false;
|
||||
if (superClass != null && !GdkMethodUtil.processCategoryMethods(((GrClosableBlock)run), processor, state, superClass)) return false;
|
||||
}
|
||||
if (gpp && run instanceof GrTypeDefinition) {
|
||||
final GrTypeDefinition typeDefinition = (GrTypeDefinition)run;
|
||||
if (!GdkMethodUtil.processCategoryMethods(typeDefinition, processor, typeDefinition, typeDefinition)) return false;
|
||||
state = state.put(ResolverProcessor.RESOLVE_CONTEXT, typeDefinition);
|
||||
if (!GdkMethodUtil.processCategoryMethods(typeDefinition, processor, state, typeDefinition)) return false;
|
||||
}
|
||||
run = run.getContext();
|
||||
}
|
||||
@@ -410,13 +390,13 @@ public class ResolveUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean processUseAnnotation(GroovyPsiElement place, PsiScopeProcessor processor) {
|
||||
private static boolean processUseAnnotation(GroovyPsiElement place, PsiScopeProcessor processor, ResolveState state) {
|
||||
PsiAnnotation use = AnnotatedContextFilter.findContextAnnotation(place, GroovyCommonClassNames.GROOVY_LANG_USE);
|
||||
if (use != null) {
|
||||
for (PsiElement element : PsiElementCategory.asList(use.findDeclaredAttributeValue("value"))) {
|
||||
if (element instanceof GrReferenceExpression) {
|
||||
PsiElement resolve = ((GrReferenceExpression)element).resolve();
|
||||
if (resolve instanceof PsiClass && !GdkMethodUtil.processCategoryMethods(place, processor, null, (PsiClass)resolve)) {
|
||||
if (resolve instanceof PsiClass && !GdkMethodUtil.processCategoryMethods(place, processor, state, (PsiClass)resolve)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -687,7 +667,7 @@ public class ResolveUtil {
|
||||
public static PsiType extractReturnTypeFromCandidate(GroovyResolveResult candidate, GrExpression expression, @Nullable PsiType[] args) {
|
||||
final PsiElement element = candidate.getElement();
|
||||
if (element instanceof PsiMethod && !candidate.isInvokedOnProperty()) {
|
||||
return TypesUtil.substituteBoxAndNormalizeType(getSmartReturnType((PsiMethod)element), candidate.getSubstitutor(), expression);
|
||||
return TypesUtil.substituteBoxAndNormalizeType(getSmartReturnType((PsiMethod)element), candidate.getSubstitutor(), candidate.getSpreadState(), expression);
|
||||
}
|
||||
|
||||
final PsiType type;
|
||||
@@ -703,7 +683,7 @@ public class ResolveUtil {
|
||||
if (type instanceof GrClosureType) {
|
||||
final GrSignature signature = ((GrClosureType)type).getSignature();
|
||||
PsiType returnType = GrClosureSignatureUtil.getReturnType(signature, args, expression);
|
||||
return TypesUtil.substituteBoxAndNormalizeType(returnType, candidate.getSubstitutor(), expression);
|
||||
return TypesUtil.substituteBoxAndNormalizeType(returnType, candidate.getSubstitutor(), candidate.getSpreadState(), expression);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+3
-1
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
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.SpreadState;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
|
||||
@@ -78,9 +79,10 @@ public class AccessorResolverProcessor extends MethodResolverProcessor {
|
||||
}
|
||||
boolean isAccessible = isAccessible(method);
|
||||
final GroovyPsiElement resolveContext = state.get(RESOLVE_CONTEXT);
|
||||
final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
|
||||
boolean isStaticsOK = isStaticsOK(method, resolveContext, true);
|
||||
final GroovyResolveResultImpl candidate =
|
||||
new GroovyResolveResultImpl(method, resolveContext, substitutor, isAccessible, isStaticsOK, true);
|
||||
new GroovyResolveResultImpl(method, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK, true);
|
||||
if (isAccessible && isStaticsOK) {
|
||||
addCandidate(candidate);
|
||||
return method instanceof GrGdkMethod; //don't stop searching if we found only gdk method
|
||||
|
||||
+5
-2
@@ -27,6 +27,7 @@ import org.jetbrains.plugins.groovy.gpp.GppClosureParameterTypeProvider;
|
||||
import org.jetbrains.plugins.groovy.gpp.GppTypeConverter;
|
||||
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.SpreadState;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
|
||||
@@ -100,12 +101,14 @@ public class MethodResolverProcessor extends ResolverProcessor {
|
||||
}
|
||||
boolean isAccessible = isAccessible(method);
|
||||
GroovyPsiElement resolveContext = state.get(RESOLVE_CONTEXT);
|
||||
final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
|
||||
|
||||
boolean isStaticsOK = isStaticsOK(method, resolveContext, true);
|
||||
if (!myAllVariants && isStaticsOK && isAccessible &&
|
||||
PsiUtil.isApplicable(myArgumentTypes, method, substitutor, (GroovyPsiElement)myPlace, myByShape)) {
|
||||
addCandidate(new GroovyResolveResultImpl(method, resolveContext, substitutor, isAccessible, isStaticsOK));
|
||||
addCandidate(new GroovyResolveResultImpl(method, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK));
|
||||
} else {
|
||||
myInapplicableCandidates.add(new GroovyResolveResultImpl(method, resolveContext, substitutor, isAccessible, isStaticsOK));
|
||||
myInapplicableCandidates.add(new GroovyResolveResultImpl(method, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
+3
-1
@@ -26,6 +26,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
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.SpreadState;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
|
||||
@@ -97,8 +98,9 @@ public class ResolverProcessor implements PsiScopeProcessor, NameHint, ClassHint
|
||||
|
||||
boolean isAccessible = isAccessible(namedElement);
|
||||
final GroovyPsiElement resolveContext = state.get(RESOLVE_CONTEXT);
|
||||
final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
|
||||
boolean isStaticsOK = isStaticsOK(namedElement, resolveContext, true);
|
||||
addCandidate(new GroovyResolveResultImpl(namedElement, resolveContext, substitutor, isAccessible, isStaticsOK));
|
||||
addCandidate(new GroovyResolveResultImpl(namedElement, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK));
|
||||
return !isAccessible || !isStaticsOK;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -180,7 +180,7 @@ public class ResolveMethodTest extends GroovyResolveTestCase {
|
||||
assertTrue(type instanceof PsiClassType);
|
||||
PsiClass clazz = ((PsiClassType) type).resolve();
|
||||
assertNotNull(clazz);
|
||||
assertEquals("java.util.List", clazz.getQualifiedName());
|
||||
assertEquals("java.util.ArrayList", clazz.getQualifiedName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
+51
@@ -426,6 +426,57 @@ print ma<caret>p
|
||||
''', "$JAVA_UTIL_MAP<$JAVA_LANG_STRING,$JAVA_LANG_STRING>")
|
||||
}
|
||||
|
||||
void testSpread1() {
|
||||
myFixture.addClass('''\
|
||||
class A {
|
||||
String getString() {return "a";}
|
||||
}''')
|
||||
doTest('''\
|
||||
[new A()].stri<caret>ng
|
||||
''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_STRING>")
|
||||
}
|
||||
|
||||
void testSpread2() {
|
||||
|
||||
myFixture.addClass('''\
|
||||
class A {
|
||||
String getString() {return "a";}
|
||||
}''')
|
||||
doTest('''\
|
||||
class Cat {
|
||||
static getFoo(String b) {2}
|
||||
}
|
||||
use(Cat) {
|
||||
[new A()].string.fo<caret>o
|
||||
}
|
||||
''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_INTEGER>")
|
||||
}
|
||||
|
||||
void testSpread3() {
|
||||
myFixture.addClass('''\
|
||||
class A {
|
||||
String getString() {return "a";}
|
||||
}''')
|
||||
doTest('''\
|
||||
[[new A()]].stri<caret>ng
|
||||
''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_STRING>>")
|
||||
}
|
||||
|
||||
void testSpread4() {
|
||||
myFixture.addClass('''\
|
||||
class A {
|
||||
String getString() {return "a";}
|
||||
}''')
|
||||
doTest('''\
|
||||
class Cat {
|
||||
static getFoo(String b) {2}
|
||||
}
|
||||
|
||||
use(Cat){
|
||||
[[new A()]].string.fo<caret>o
|
||||
}
|
||||
''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_INTEGER>>")
|
||||
}
|
||||
|
||||
private void doTest(String text, String type) {
|
||||
def file = myFixture.configureByText('_.groovy', text)
|
||||
|
||||
Reference in New Issue
Block a user