Merge branch 'dany/operator-assignment'

# Conflicts:
#	plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java
This commit is contained in:
Daniil Ovchinnikov
2017-01-25 15:16:19 +03:00
11 changed files with 289 additions and 110 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMember;
import com.intellij.psi.PsiType;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -50,4 +51,10 @@ public interface GrReferenceExpression extends GrExpression, GrReferenceElement<
GrReferenceExpression bindToElementViaStaticImport(@NotNull PsiMember member);
@Nullable
@Override
default PsiType getType() { return getType(false); }
@Nullable
PsiType getType(boolean forceRValue);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -43,6 +43,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.statements.GrOperatorExpressio
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrBindingVariable;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import java.util.Objects;
import java.util.concurrent.ConcurrentMap;
/**
@@ -61,7 +62,7 @@ public class GrAssignmentExpressionImpl extends GrOperatorExpressionImpl impleme
@Override
@NotNull
public GrExpression getLValue() {
return findExpressionChild(this);
return Objects.requireNonNull(findExpressionChild(this));
}
@Override
@@ -161,6 +162,16 @@ public class GrAssignmentExpressionImpl extends GrOperatorExpressionImpl impleme
return rValue == null ? null : rValue.getType();
}
@Nullable
@Override
public PsiType getType() {
if (TokenSets.ASSIGNMENTS_TO_OPERATORS.containsKey(getOperationTokenType())) {
return super.getType();
} else {
return getRightType();
}
}
private static final ResolveCache.PolyVariantResolver<GrAssignmentExpressionImpl> RESOLVER = new ResolveCache.PolyVariantResolver<GrAssignmentExpressionImpl>() {
@NotNull
@Override
@@ -177,6 +188,9 @@ public class GrAssignmentExpressionImpl extends GrOperatorExpressionImpl impleme
*/
lType = ((GrIndexProperty)lValue).getGetterType();
}
else if (lValue instanceof GrReferenceExpression) {
lType = ((GrReferenceExpression)lValue).getType(true);
}
else {
lType = lValue.getType();
}
@@ -18,15 +18,15 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.AtomicNotNullLazyValue;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.ResolveCache.PolyVariantResolver;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.profiling.ResolveProfiler;
@@ -60,6 +60,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProces
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* @author ilyas
@@ -72,6 +73,14 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
super(node);
}
private final NotNullLazyValue<GrReferenceExpressionReference> myFakeGetterReference = AtomicNotNullLazyValue.createValue(
() -> new GrReferenceExpressionReference(this, true)
);
private final NotNullLazyValue<GrReferenceExpressionReference> myFakeReference = AtomicNotNullLazyValue.createValue(
() -> new GrReferenceExpressionReference(this, false)
);
@NotNull
private static List<GroovyResolveResult> filterMembersFromSuperClasses(GroovyResolveResult[] results) {
List<GroovyResolveResult> filtered = new ArrayList<>();
@@ -97,7 +106,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
@NotNull
public GroovyResolveResult[] getCallVariants(@Nullable GrExpression upToArgument) {
return _resolve(false, true, upToArgument);
return _resolve(false, false, true, upToArgument);
}
@Override
@@ -195,19 +204,16 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
return "Reference expression";
}
private static final PolyVariantResolver<GrReferenceExpressionImpl> POLY_RESOLVER = new PolyVariantResolver<GrReferenceExpressionImpl>() {
@Override
@NotNull
public GroovyResolveResult[] resolve(@NotNull final GrReferenceExpressionImpl refExpr, final boolean incompleteCode) {
return refExpr.doPolyResolve(incompleteCode);
}
};
private static final OurTypesCalculator TYPES_CALCULATOR = new OurTypesCalculator();
@Override
@Nullable
public PsiType getNominalType() {
final GroovyResolveResult resolveResult = advancedResolve();
return getNominalType(false);
}
@Nullable
private PsiType getNominalType(boolean forceRValue) {
final GroovyResolveResult resolveResult = PsiImplUtil.extractUniqueResult(multiResolve(false, forceRValue));
PsiElement resolved = resolveResult.getElement();
for (GrReferenceTypeEnhancer enhancer : GrReferenceTypeEnhancer.EP_NAME.getExtensions()) {
@@ -361,72 +367,69 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
return null;
}
private static final class OurTypesCalculator implements Function<GrReferenceExpressionImpl, PsiType> {
@Override
@Nullable
public PsiType fun(GrReferenceExpressionImpl refExpr) {
final PsiElement resolved = refExpr.resolve();
@Nullable
private static PsiType calculate(@NotNull GrReferenceExpressionImpl refExpr, boolean forceRValue) {
final GroovyResolveResult[] results = refExpr.multiResolve(false, forceRValue);
final GroovyResolveResult result = PsiImplUtil.extractUniqueResult(results);
final PsiElement resolved = result.getElement();
for (GrExpressionTypeCalculator calculator : GrExpressionTypeCalculator.EP_NAME.getExtensions()) {
PsiType type = calculator.calculateType(refExpr, resolved);
if (type != null) return type;
for (GrExpressionTypeCalculator calculator : GrExpressionTypeCalculator.EP_NAME.getExtensions()) {
PsiType type = calculator.calculateType(refExpr, resolved);
if (type != null) return type;
}
if (ResolveUtil.isClassReference(refExpr)) {
GrExpression qualifier = refExpr.getQualifier();
LOG.assertTrue(qualifier != null);
return qualifier.getType();
}
if (PsiUtil.isCompileStatic(refExpr)) {
final PsiType type;
if (resolved instanceof GrField) {
type = ((GrField)resolved).getType();
}
if (ResolveUtil.isClassReference(refExpr)) {
GrExpression qualifier = refExpr.getQualifier();
LOG.assertTrue(qualifier != null);
return qualifier.getType();
else if (resolved instanceof GrVariable) {
type = ((GrVariable)resolved).getDeclaredType();
}
else if (resolved instanceof GrAccessorMethod) {
type = ((GrAccessorMethod)resolved).getProperty().getType();
}
else {
type = null;
}
if (type != null) {
return result.getSubstitutor().substitute(type);
}
}
if (PsiUtil.isCompileStatic(refExpr)) {
final GroovyResolveResult resolveResult = refExpr.advancedResolve();
final PsiElement resolvedF = resolveResult.getElement();
final PsiType type;
if (resolvedF instanceof GrField) {
type = ((GrField)resolvedF).getType();
}
else if (resolvedF instanceof GrVariable) {
type = ((GrVariable)resolvedF).getDeclaredType();
}
else if (resolvedF instanceof GrAccessorMethod) {
type = ((GrAccessorMethod)resolvedF).getProperty().getType();
}
else {
type = null;
}
if (type != null) {
return resolveResult.getSubstitutor().substitute(type);
final PsiType nominal = refExpr.getNominalType(forceRValue);
Boolean reassigned = GrReassignedLocalVarsChecker.isReassignedVar(refExpr);
if (reassigned != null && reassigned.booleanValue()) {
return GrReassignedLocalVarsChecker.getReassignedVarType(refExpr, true);
}
final PsiType inferred = getInferredTypes(refExpr, resolved);
if (inferred == null) {
if (nominal == null) {
//inside nested closure we could still try to infer from variable initializer. Not sound, but makes sense
if (resolved instanceof GrVariable) {
LOG.assertTrue(resolved.isValid());
return ((GrVariable)resolved).getTypeGroovy();
}
}
final PsiType nominal = refExpr.getNominalType();
Boolean reassigned = GrReassignedLocalVarsChecker.isReassignedVar(refExpr);
if (reassigned != null && reassigned.booleanValue()) {
return GrReassignedLocalVarsChecker.getReassignedVarType(refExpr, true);
}
final PsiType inferred = getInferredTypes(refExpr, resolved);
if (inferred == null) {
if (nominal == null) {
//inside nested closure we could still try to infer from variable initializer. Not sound, but makes sense
if (resolved instanceof GrVariable) {
LOG.assertTrue(resolved.isValid());
return ((GrVariable)resolved).getTypeGroovy();
}
}
return nominal;
}
if (nominal == null) return inferred;
if (!TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(nominal), inferred, false)) {
if (resolved instanceof GrVariable && ((GrVariable)resolved).getTypeElementGroovy() != null) {
return nominal;
}
if (nominal == null) return inferred;
if (!TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(nominal), inferred, false)) {
if (resolved instanceof GrVariable && ((GrVariable)resolved).getTypeElementGroovy() != null) {
return nominal;
}
}
return inferred;
}
return inferred;
}
@Nullable
@@ -450,9 +453,17 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
return null;
}
@Nullable
@Override
public PsiType getType() {
return TypeInferenceHelper.getCurrentContext().getExpressionType(this, TYPES_CALCULATOR);
public PsiType getType(boolean forceRValue) {
if (forceRValue) {
return calculate(this, true);
}
else {
return TypeInferenceHelper.getCurrentContext().getExpressionType(
this, e -> calculate(e, false)
);
}
}
@Override
@@ -461,7 +472,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
}
@NotNull
private GroovyResolveResult[] doPolyResolve(boolean incompleteCode) {
GroovyResolveResult[] doPolyResolve(boolean incompleteCode, boolean forceRValue) {
final PsiElement nameElement = getReferenceNameElement();
final String name = getReferenceName();
if (name == null || nameElement == null) return GroovyResolveResult.EMPTY_ARRAY;
@@ -482,7 +493,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
}
}
final GroovyResolveResult[] results = _resolve(incompleteCode, false, null);
final GroovyResolveResult[] results = _resolve(forceRValue, incompleteCode, false, null);
if (results.length == 0) {
return GroovyResolveResult.EMPTY_ARRAY;
}
@@ -507,8 +518,12 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
}
@NotNull
private GroovyResolveResult[] _resolve(boolean incomplete, boolean allVariants, @Nullable GrExpression upToArgument) {
private GroovyResolveResult[] _resolve(boolean forceRValue,
boolean incomplete,
boolean allVariants,
@Nullable GrExpression upToArgument) {
final GroovyResolverProcessor processor = GroovyResolverProcessorBuilder.builder()
.setForceRValue(forceRValue)
.setIncomplete(incomplete)
.setAllVariants(allVariants)
.setUpToArgument(upToArgument)
@@ -535,22 +550,28 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
@Override
public boolean isReferenceTo(PsiElement element) {
PsiElement baseTarget = resolve();
if (getManager().areElementsEquivalent(element, baseTarget)) {
return true;
}
GroovyResolveResult[] results = multiResolve(false);
PsiElement target = GroovyTargetElementEvaluator.correctSearchTargets(baseTarget);
if (target != baseTarget && getManager().areElementsEquivalent(element, target)) {
return true;
}
if (element instanceof PsiMethod && target instanceof PsiMethod) {
PsiMethod[] superMethods = ((PsiMethod)target).findSuperMethods(false);
//noinspection SuspiciousMethodCalls
if (Arrays.asList(superMethods).contains(element)) {
for (GroovyResolveResult result : results) {
if (!result.isValidResult()) continue;
PsiElement baseTarget = result.getElement();
if (baseTarget == null) continue;
if (getManager().areElementsEquivalent(element, baseTarget)) {
return true;
}
PsiElement target = GroovyTargetElementEvaluator.correctSearchTargets(baseTarget);
if (target != baseTarget && getManager().areElementsEquivalent(element, target)) {
return true;
}
if (element instanceof PsiMethod && target instanceof PsiMethod) {
PsiMethod[] superMethods = ((PsiMethod)target).findSuperMethods(false);
//noinspection SuspiciousMethodCalls
if (Arrays.asList(superMethods).contains(element)) {
return true;
}
}
}
return false;
@@ -597,17 +618,32 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
return dot == null ? null : dot.getNode().getElementType();
}
@Override
@NotNull
public GroovyResolveResult[] multiResolve(boolean incomplete) { //incomplete means we do not take arguments into consideration
final ResolveResult[] results = TypeInferenceHelper.getCurrentContext().multiResolve(this, incomplete, POLY_RESOLVER);
return results.length == 0 ? GroovyResolveResult.EMPTY_ARRAY : (GroovyResolveResult[])results;
@Override
public GroovyResolveResult[] multiResolve(boolean incompleteCode) {
return TypeInferenceHelper.getCurrentContext().multiResolve(this, incompleteCode, (ref, incomplete) -> {
GroovyResolveResult[] regularResults = ref.multiResolve(incomplete, false);
if (PsiUtil.isLValueOfOperatorAssignment(this)) {
Set<GroovyResolveResult> result = ContainerUtil.newLinkedHashSet();
ContainerUtil.addAll(result, ref.multiResolve(incomplete, true));
ContainerUtil.addAll(result, regularResults);
return result.toArray(GroovyResolveResult.EMPTY_ARRAY);
}
else {
return regularResults;
}
});
}
@NotNull
public GroovyResolveResult[] multiResolve(boolean incomplete, boolean forceRValue) {
return (forceRValue ? myFakeGetterReference : myFakeReference).getValue().multiResolve(incomplete);
}
@Override
@NotNull
public GroovyResolveResult[] getSameNameVariants() {
return doPolyResolve(true);
return doPolyResolve(true, false);
}
@Override
@@ -0,0 +1,34 @@
/*
* Copyright 2000-2017 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.statements.expressions
import com.intellij.psi.PsiPolyVariantReferenceBase
import com.intellij.util.ArrayUtil
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper
class GrReferenceExpressionReference(private val ref: GrReferenceExpressionImpl, private val forceRValue: Boolean)
: PsiPolyVariantReferenceBase<GrReferenceExpressionImpl>(ref) {
override fun getVariants(): Array<out Any> = ArrayUtil.EMPTY_OBJECT_ARRAY
override fun multiResolve(incompleteCode: Boolean): Array<out GroovyResolveResult> {
val results = TypeInferenceHelper.getCurrentContext().multiResolve(this, incompleteCode) { ref, incomplete ->
ref.ref.doPolyResolve(incompleteCode, forceRValue)
}
return if (results.isEmpty()) GroovyResolveResult.EMPTY_ARRAY else results
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -159,6 +159,13 @@ public class PsiUtil {
return false;
}
public static boolean isLValueOfOperatorAssignment(@NotNull GrReferenceExpression element) {
PsiElement parent = PsiTreeUtil.skipParentsOfType(element, GrParenthesizedExpression.class);
return parent instanceof GrAssignmentExpression
&& ((GrAssignmentExpression)parent).getOperationTokenType() != GroovyTokenTypes.mASSIGN
&& PsiTreeUtil.isAncestor(((GrAssignmentExpression)parent).getLValue(), element, false);
}
public static boolean isApplicable(@Nullable PsiType[] argumentTypes,
PsiMethod method,
PsiSubstitutor substitutor,
@@ -280,12 +287,13 @@ public class PsiUtil {
);
}
}
else if (parent instanceof GrBinaryExpression || parent instanceof GrAssignmentExpression) {
GrExpression right = parent instanceof GrBinaryExpression
? ((GrBinaryExpression)parent).getRightOperand()
: ((GrAssignmentExpression)parent).getRValue();
else if (parent instanceof GrBinaryExpression) {
GrExpression right = ((GrBinaryExpression)parent).getRightOperand();
PsiType type = right != null ? right.getType() : null;
return new PsiType[]{notNullizeType(type, nullAsBottom, parent)};
} else if (parent instanceof GrAssignmentExpression) {
PsiType type = ((GrAssignmentExpression)parent).getType();
return new PsiType[]{notNullizeType(type, nullAsBottom, parent)};
}
return null;
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -31,7 +31,7 @@ class GroovyAllVariantsProcessor extends GroovyResolverProcessor {
GroovyAllVariantsProcessor(@NotNull GrReferenceExpression ref,
@NotNull EnumSet<GroovyResolveKind> kinds,
@Nullable GrExpression myUpToArgument) {
super(ref, kinds, myUpToArgument);
super(ref, kinds, myUpToArgument, false);
}
@NotNull
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -87,12 +87,13 @@ public abstract class GroovyResolverProcessor implements PsiScopeProcessor, Elem
GroovyResolverProcessor(@NotNull GrReferenceExpression ref,
@NotNull EnumSet<GroovyResolveKind> kinds,
@Nullable GrExpression myUpToArgument) {
@Nullable GrExpression myUpToArgument,
boolean forceRValue) {
myRef = ref;
myAcceptableKinds = kinds;
myName = getReferenceName(ref);
myIsLValue = PsiUtil.isLValue(myRef);
myIsLValue = !forceRValue && PsiUtil.isLValue(myRef);
myThisType = PsiImplUtil.getQualifierType(ref);
myTypeArguments = ref.getTypeArguments();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -30,6 +30,7 @@ public final class GroovyResolverProcessorBuilder {
private boolean myIncomplete = false;
private boolean myAllVariants = false;
private GrExpression myUpToArgument = null;
private boolean myForceRValue = false;
@NotNull
public GroovyResolverProcessor build(GrReferenceExpression ref) {
@@ -38,7 +39,7 @@ public final class GroovyResolverProcessorBuilder {
return new GroovyAllVariantsProcessor(ref, kinds, myUpToArgument);
}
else {
return new GroovyResolverProcessorImpl(ref, kinds);
return new GroovyResolverProcessorImpl(ref, kinds, myForceRValue);
}
}
@@ -64,6 +65,12 @@ public final class GroovyResolverProcessorBuilder {
return this;
}
@NotNull
public GroovyResolverProcessorBuilder setForceRValue(boolean forceRValue) {
myForceRValue = forceRValue;
return this;
}
@NotNull
private static EnumSet<GroovyResolveKind> computeKinds(@NotNull GrReferenceExpression ref) {
if (ref.hasAt()) return EnumSet.of(FIELD);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -38,8 +38,8 @@ class GroovyResolverProcessorImpl extends GroovyResolverProcessor implements GrM
private final boolean myIsPartOfFqn;
GroovyResolverProcessorImpl(@NotNull final GrReferenceExpression ref, @NotNull EnumSet<GroovyResolveKind> kinds) {
super(ref, kinds, null);
GroovyResolverProcessorImpl(@NotNull final GrReferenceExpression ref, @NotNull EnumSet<GroovyResolveKind> kinds, boolean forceRValue) {
super(ref, kinds, null, forceRValue);
myIsPartOfFqn = ResolveUtil.isPartOfFQN(ref);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -24,6 +24,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.encapsulateFields.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -31,6 +32,7 @@ import org.jetbrains.plugins.groovy.codeInspection.utils.JavaStylePropertiesUtil
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
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.statements.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
@@ -151,7 +153,8 @@ public class GroovyEncapsulateFieldHelper extends EncapsulateFieldHelper {
PsiClass accessObjectClass = getAccessObject(expr);
final PsiResolveHelper helper = JavaPsiFacade.getInstance((expr).getProject()).getResolveHelper();
if (helper.isAccessible(fieldDescriptor.getField(), newModifierList, expr, accessObjectClass, null)) {
if (expr.resolve() instanceof PsiMethod) {
GroovyResolveResult[] results = expr.multiResolve(false);
if (ContainerUtil.or(results, it -> it.isValidResult() && it.getElement() instanceof PsiMethod)) {
addMemberOperator(expr, field);
}
return true;
@@ -0,0 +1,69 @@
/*
* Copyright 2000-2017 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.resolve
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.plugins.groovy.GroovyLightProjectDescriptor
import org.jetbrains.plugins.groovy.codeInspection.GroovyUnusedDeclarationInspection
import org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.GrUnresolvedAccessInspection
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
class ResolveOperatorAssignmentTest extends GroovyResolveTestCase {
final LightProjectDescriptor projectDescriptor = GroovyLightProjectDescriptor.GROOVY_LATEST
void 'test resolve both getter & setter'() {
fixture.with {
configureByText '_.groovy', '''\
class A {
C plus(B b) {b}
}
class B {}
class C {}
class Foo {
A getProp() {}
Long setProp(C c) {c}
}
def foo = new Foo()
foo.pr<caret>op += new B()
'''
enableInspections GrUnresolvedAccessInspection, GroovyUnusedDeclarationInspection
checkHighlighting()
def ref = file.findReferenceAt(editor.caretModel.offset) as GrReferenceExpression
def results = ref.multiResolve(false)
assert results.size() == 2
for (result in results) {
assert result.isValidResult()
}
}
}
void 'type reassigned'() {
fixture.with {
def file = configureByText '_.groovy', '''\
class ClassWithPlus {
AnotherClass plus(a) {new AnotherClass()}
}
class AnotherClass {}
def c = new ClassWithPlus()
c += 1
<caret>c
'''
def expression = file.children.last() as GrReferenceExpression
assert expression.type.equalsToText("AnotherClass")
}
}
}