[groovy] compute Closure.getOwner() type without light variable

This commit is contained in:
Daniil Ovchinnikov
2017-11-27 17:20:29 +03:00
parent 80f663b084
commit 229c8a0711
6 changed files with 48 additions and 76 deletions
@@ -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();
}
@@ -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
@@ -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<GrReferenceExpression> {
class GrClosureOwnerDelegateTypeCalculator : GrTypeCalculator<GrReferenceExpression> {
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
}
}
+1 -1
View File
@@ -171,7 +171,7 @@
implementation="org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path.GrDGMTypeCalculator"/>
<typeCalculator forClass="org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression"
implementationClass="org.jetbrains.plugins.groovy.lang.typing.GrClosureDelegateTypeCalculator"/>
implementationClass="org.jetbrains.plugins.groovy.lang.typing.GrClosureOwnerDelegateTypeCalculator"/>
<typeCalculator forClass="org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall"
implementationClass="org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path.GrDescriptorReturnTypeCalculator"/>
@@ -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 {
@@ -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 = {
<caret>owner
}
}
''', 'W'
}
}