diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrReferenceExpression.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrReferenceExpression.java index 2efdcb11bf08..3dba0a5e718b 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrReferenceExpression.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrReferenceExpression.java @@ -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); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrAssignmentExpressionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrAssignmentExpressionImpl.java index 15bb02431b5d..b7e9586bdc49 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrAssignmentExpressionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrAssignmentExpressionImpl.java @@ -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 RESOLVER = new ResolveCache.PolyVariantResolver() { @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(); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index a2fef0e4046d..50407f727026 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -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 myFakeGetterReference = AtomicNotNullLazyValue.createValue( + () -> new GrReferenceExpressionReference(this, true) + ); + + private final NotNullLazyValue myFakeReference = AtomicNotNullLazyValue.createValue( + () -> new GrReferenceExpressionReference(this, false) + ); + @NotNull private static List filterMembersFromSuperClasses(GroovyResolveResult[] results) { List filtered = new ArrayList<>(); @@ -97,7 +106,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl POLY_RESOLVER = new PolyVariantResolver() { - @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 { - @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 calculate(e, false) + ); + } } @Override @@ -461,7 +472,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl { + GroovyResolveResult[] regularResults = ref.multiResolve(incomplete, false); + if (PsiUtil.isLValueOfOperatorAssignment(this)) { + Set 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 diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionReference.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionReference.kt new file mode 100644 index 000000000000..fd5846dba7d3 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionReference.kt @@ -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(ref) { + + override fun getVariants(): Array = ArrayUtil.EMPTY_OBJECT_ARRAY + + override fun multiResolve(incompleteCode: Boolean): Array { + val results = TypeInferenceHelper.getCurrentContext().multiResolve(this, incompleteCode) { ref, incomplete -> + ref.ref.doPolyResolve(incompleteCode, forceRValue) + } + return if (results.isEmpty()) GroovyResolveResult.EMPTY_ARRAY else results + } +} \ No newline at end of file diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index 464a0452fa97..897bad9caabc 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -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; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyAllVariantsProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyAllVariantsProcessor.java index 4d36eff7f746..2d7b25cd15b6 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyAllVariantsProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyAllVariantsProcessor.java @@ -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 kinds, @Nullable GrExpression myUpToArgument) { - super(ref, kinds, myUpToArgument); + super(ref, kinds, myUpToArgument, false); } @NotNull diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java index 6900497a999b..5ad69f61e043 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessor.java @@ -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 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(); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessorBuilder.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessorBuilder.java index 9c438c0d940d..0bdeb651b1c0 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessorBuilder.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessorBuilder.java @@ -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 computeKinds(@NotNull GrReferenceExpression ref) { if (ref.hasAt()) return EnumSet.of(FIELD); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessorImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessorImpl.java index ad623b0ffb64..0b2c5b65a397 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessorImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyResolverProcessorImpl.java @@ -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 kinds) { - super(ref, kinds, null); + GroovyResolverProcessorImpl(@NotNull final GrReferenceExpression ref, @NotNull EnumSet kinds, boolean forceRValue) { + super(ref, kinds, null, forceRValue); myIsPartOfFqn = ResolveUtil.isPartOfFQN(ref); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/encapsulateFields/GroovyEncapsulateFieldHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/encapsulateFields/GroovyEncapsulateFieldHelper.java index c7dd2c63fd46..38869441db24 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/encapsulateFields/GroovyEncapsulateFieldHelper.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/encapsulateFields/GroovyEncapsulateFieldHelper.java @@ -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; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveOperatorAssignmentTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveOperatorAssignmentTest.groovy new file mode 100644 index 000000000000..44049931a93f --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveOperatorAssignmentTest.groovy @@ -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.prop += 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 +c +''' + def expression = file.children.last() as GrReferenceExpression + assert expression.type.equalsToText("AnotherClass") + } + } +}