diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/blocks/GrClosableBlock.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/blocks/GrClosableBlock.java index 8a6423db1f93..baec5f638362 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/blocks/GrClosableBlock.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/blocks/GrClosableBlock.java @@ -1,18 +1,4 @@ -/* - * 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks; @@ -63,4 +49,7 @@ public interface GrClosableBlock extends GrExpression, GrCodeBlock, GrParameters @NotNull final ResolveState _state, @Nullable final PsiElement lastParent, @NotNull final PsiElement place); + + @Nullable + PsiType getOwnerType(); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java index e3d3c38c1301..4fa82f92c6d0 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrClosableBlockImpl.java @@ -1,18 +1,4 @@ -/* - * 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.psi.impl.statements.blocks; @@ -21,7 +7,7 @@ import com.intellij.psi.*; import com.intellij.psi.scope.ElementClassHint; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValueProvider.Result; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.psi.util.PsiTreeUtil; @@ -43,10 +29,8 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterLi import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; import org.jetbrains.plugins.groovy.lang.psi.impl.*; -import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.params.GrParameterListImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.ClosureSyntheticParameter; -import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightVariable; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.resolve.MethodTypeInferencer; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -98,7 +82,6 @@ public class GrClosableBlockImpl extends GrBlockImpl implements GrClosableBlock if (!super.processDeclarations(processor, state, lastParent, place)) return false; if (!processParameters(processor, state, place)) return false; - if (ResolveUtil.shouldProcessProperties(processor.getHint(ElementClassHint.KEY)) && !ResolveUtil.processElement(processor, getOwner(), state)) return false; if (!processClosureClassMembers(processor, state, lastParent, place)) return false; return true; @@ -295,28 +278,28 @@ public class GrClosableBlockImpl extends GrBlockImpl implements GrClosableBlock return res; } - private PsiVariable getOwner() { - return CachedValuesManager.getCachedValue(this, () -> { - final GroovyPsiElement context = PsiTreeUtil.getParentOfType(this, GrTypeDefinition.class, GrClosableBlock.class, GroovyFile.class); - final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); - PsiType type = null; - if (context instanceof GrTypeDefinition) { - type = factory.createType((PsiClass)context); - } - else if (context instanceof GrClosableBlock) { - type = GrClosureType.create((GrClosableBlock)context, true); - } - else if (context instanceof GroovyFile) { - final PsiClass scriptClass = ((GroovyFile)context).getScriptClass(); - if (scriptClass != null && GroovyNamesUtil.isIdentifier(scriptClass.getName())) type = factory.createType(scriptClass); - } - if (type == null) { - type = TypesUtil.getJavaLangObject(this); - } + @Nullable + @Override + public PsiType getOwnerType() { + return CachedValuesManager.getCachedValue(this, () -> Result.create(doGetOwnerType(), PsiModificationTracker.MODIFICATION_COUNT)); + } - PsiVariable owner = new GrLightVariable(getManager(), OWNER_NAME, type, this); - return CachedValueProvider.Result.create(owner, PsiModificationTracker.MODIFICATION_COUNT); - }); + @Nullable + private PsiType doGetOwnerType() { + final GroovyPsiElement context = PsiTreeUtil.getParentOfType(this, GrTypeDefinition.class, GrClosableBlock.class, GroovyFile.class); + final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory(); + if (context instanceof GrTypeDefinition) { + return factory.createType((PsiClass)context); + } + else if (context instanceof GrClosableBlock) { + return ((GrClosableBlock)context).getType(); + } + else if (context instanceof GroovyFile) { + final PsiClass scriptClass = ((GroovyFile)context).getScriptClass(); + if (scriptClass != null && GroovyNamesUtil.isIdentifier(scriptClass.getName())) return factory.createType(scriptClass); + } + + return null; } @Override diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/GrClosureDelegateTypeCalculator.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/GrClosureOwnerDelegateTypeCalculator.kt similarity index 54% rename from plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/GrClosureDelegateTypeCalculator.kt rename to plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/GrClosureOwnerDelegateTypeCalculator.kt index d5f96aa444bc..88b098b78dec 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/GrClosureDelegateTypeCalculator.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/GrClosureOwnerDelegateTypeCalculator.kt @@ -1,18 +1,4 @@ -/* - * 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. - */ +// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.typing import com.intellij.psi.JavaPsiFacade @@ -24,16 +10,21 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrRefere import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames.GROOVY_LANG_CLOSURE import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.getDelegatesToInfo -class GrClosureDelegateTypeCalculator : GrTypeCalculator { +class GrClosureOwnerDelegateTypeCalculator : GrTypeCalculator { override fun getType(expression: GrReferenceExpression): PsiType? { val method = expression.resolve() as? PsiMethod ?: return null - if ("getDelegate" != method.name || method.parameterList.parametersCount != 0) return null + + val methodName = method.name + val delegate = "getDelegate" == methodName + if (!delegate && "getOwner" != methodName) return null + + if (method.parameterList.parametersCount != 0) return null val closureClass = JavaPsiFacade.getInstance(expression.project).findClass(GROOVY_LANG_CLOSURE, expression.resolveScope) if (closureClass == null || closureClass != method.containingClass) return null val closure = PsiTreeUtil.getParentOfType(expression, GrClosableBlock::class.java) ?: return null - return getDelegatesToInfo(closure)?.typeToDelegate + return if (delegate) getDelegatesToInfo(closure)?.typeToDelegate else closure.ownerType } } diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 49f952083ed9..44b1aabe9bce 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -171,7 +171,7 @@ implementation="org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path.GrDGMTypeCalculator"/> + implementationClass="org.jetbrains.plugins.groovy.lang.typing.GrClosureOwnerDelegateTypeCalculator"/> diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy index a2bb8dd0a64a..06dc4218b07c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolvePropertyTest.groovy @@ -37,8 +37,7 @@ class ResolvePropertyTest extends GroovyResolveTestCase { void testClosureOwner() throws Exception { PsiReference ref = configureByFile("closureOwner/A.groovy") PsiElement resolved = ref.resolve() - assertInstanceOf(resolved, PsiVariable) - assertEquals((resolved as PsiVariable).type.canonicalText, "W") + assertInstanceOf(resolved, PsiMethod) } void testLocal1() throws Exception { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy index 2e132bf8dfd1..b984fcab2441 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.groovy @@ -818,4 +818,14 @@ def bar() { void 'test enum values() type'() { doExprTest 'enum E {}; E.values()', 'E[]' } + + void 'test closure owner type'() { + doTest '''\ +class W { + def c = { + owner + } +} +''', 'W' + } }