From 60632b102f048803ddbe7258d43d52bf8375e207 Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Mon, 18 Apr 2011 13:35:57 +0400 Subject: [PATCH] EA-26560 - SOE: GroovyPsiElementImpl.acceptGroovyChildren --- .../controlFlow/impl/ControlFlowBuilder.java | 38 +++++++++---------- .../psi/controlFlow/impl/InstructionImpl.java | 5 +-- .../processors/MethodResolverProcessor.java | 31 ++++++++++++--- .../lang/resolve/TypeInferenceTest.java | 4 ++ .../testdata/resolve/inference/noSOF/A.groovy | 10 +++++ 5 files changed, 60 insertions(+), 28 deletions(-) create mode 100644 plugins/groovy/testdata/resolve/inference/noSOF/A.groovy diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java index 0d8005882c0e..619394ffaf48 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java @@ -24,7 +24,7 @@ import com.intellij.psi.PsiType; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; -import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; +import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; @@ -270,25 +270,25 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { public void visitThrowStatement(GrThrowStatement throwStatement) { final GrExpression exception = throwStatement.getException(); - if (exception != null) { - exception.accept(this); - final InstructionImpl throwInstruction = startNode(throwStatement); - flowAbrupted(); - final PsiType type = exception.getNominalType(); - if (type != null) { - ExceptionInfo info = findCatch(type); - if (info != null) { - info.myThrowers.add(throwInstruction); - } - else { - addPendingEdge(null, throwInstruction); - } + if (exception == null) return; + + exception.accept(this); + final InstructionImpl throwInstruction = startNode(throwStatement); + flowAbrupted(); + final PsiType type = exception.getNominalType(); + if (type != null) { + ExceptionInfo info = findCatch(type); + if (info != null) { + info.myThrowers.add(throwInstruction); } else { addPendingEdge(null, throwInstruction); } - finishNode(throwInstruction); } + else { + addPendingEdge(null, throwInstruction); + } + finishNode(throwInstruction); } private void flowAbrupted() { @@ -317,7 +317,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { public void visitAssignmentExpression(GrAssignmentExpression expression) { GrExpression lValue = expression.getLValue(); - if (expression.getOperationToken() != GroovyElementTypes.mASSIGN) { + if (expression.getOperationToken() != GroovyTokenTypes.mASSIGN) { if (lValue instanceof GrReferenceExpression) { ReadWriteVariableInstructionImpl instruction = new ReadWriteVariableInstructionImpl((GrReferenceExpression)lValue, myInstructionNumber++, false); @@ -343,7 +343,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { public void visitUnaryExpression(GrUnaryExpression expression) { final GrExpression operand = expression.getOperand(); if (operand != null) { - final boolean negation = expression.getOperationTokenType() == GroovyElementTypes.mLNOT; + final boolean negation = expression.getOperationTokenType() == GroovyTokenTypes.mLNOT; if (negation) { myNegate = !myNegate; } @@ -505,7 +505,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { } //add edge when instruction.getElement() is not contained in scopeWhenAdded - private void addPendingEdge(GroovyPsiElement scopeWhenAdded, InstructionImpl instruction) { + private void addPendingEdge(@Nullable GroovyPsiElement scopeWhenAdded, InstructionImpl instruction) { if (instruction == null) return; int i = 0; @@ -662,7 +662,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { } } - private InstructionImpl startNode(GroovyPsiElement element) { + private InstructionImpl startNode(@Nullable GroovyPsiElement element) { return startNode(element, true); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/InstructionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/InstructionImpl.java index 8c8b63403bb7..cff6e4aed68b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/InstructionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/InstructionImpl.java @@ -15,7 +15,6 @@ */ package org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.controlFlow.CallEnvironment; @@ -29,8 +28,6 @@ import java.util.Stack; * @author ven */ public class InstructionImpl implements Instruction, Cloneable { - private static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.InstructionImpl"); - ArrayList myPred = new ArrayList(); ArrayList mySucc = new ArrayList(); @@ -43,7 +40,7 @@ public class InstructionImpl implements Instruction, Cloneable { return myPsiElement; } - public InstructionImpl(PsiElement element, int num) { + public InstructionImpl(@Nullable PsiElement element, int num) { myPsiElement = element; myNumber = num; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java index dfa830e0609d..c804e6f7336b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java @@ -27,14 +27,17 @@ import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; 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.statements.GrStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrThrowStatement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter; @@ -63,7 +66,8 @@ public class MethodResolverProcessor extends ResolverProcessor { private final boolean myIsConstructor; private boolean myStopExecuting = false; - private final Set myExitPoints = new HashSet(); + private Set myExitPoints; + private final boolean canNotBeExitPoint; public MethodResolverProcessor(String name, GroovyPsiElement place, boolean isConstructor, PsiType thisType, @Nullable PsiType[] argumentTypes, PsiType[] typeArguments) { this(name, place, isConstructor, thisType, argumentTypes, typeArguments, false); @@ -75,11 +79,16 @@ public class MethodResolverProcessor extends ResolverProcessor { myArgumentTypes = argumentTypes; myTypeArguments = typeArguments; myAllVariants = allVariants; + canNotBeExitPoint = !canBexExitPoint(place); + } - final GrMethod method = PsiTreeUtil.getParentOfType(myPlace, GrMethod.class, true, GrClosableBlock.class); - if (method != null) { - myExitPoints.addAll(ControlFlowUtils.collectReturns(method.getBlock())); + private static boolean canBexExitPoint(PsiElement place) { + while (place != null) { + if (place instanceof GrMethod || place instanceof GrClosableBlock) return true; + if (place instanceof GrThrowStatement || place instanceof GrTypeDefinitionBody || place instanceof GroovyFile) return false; + place = place.getParent(); } + return false; } public boolean execute(PsiElement element, ResolveState state) { @@ -228,7 +237,7 @@ public class MethodResolverProcessor extends ResolverProcessor { PsiElement call = myPlace.getParent(); final PsiElement parent = call.getParent(); PsiType rType = null; - if (parent instanceof GrReturnStatement || myExitPoints.contains(call)) { + if (parent instanceof GrReturnStatement || exitsContains(call)) { final GrMethod method = PsiTreeUtil.getParentOfType(parent, GrMethod.class, true, GrClosableBlock.class); if (method != null) rType = method.getReturnType(); } @@ -241,6 +250,18 @@ public class MethodResolverProcessor extends ResolverProcessor { return rType; } + private boolean exitsContains(PsiElement call) { + if (canNotBeExitPoint) return false; + if (myExitPoints == null) { + final GrMethod method = PsiTreeUtil.getParentOfType(myPlace, GrMethod.class, true, GrClosableBlock.class); + myExitPoints = new HashSet(); + if (method != null) { + myExitPoints.addAll(ControlFlowUtils.collectReturns(method.getBlock())); + } + } + return myExitPoints.contains(call); + } + @NotNull public GroovyResolveResult[] getCandidates() { if (!myAllVariants && super.hasCandidates()) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.java index f70944f1948a..5ee85b4dca43 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/TypeInferenceTest.java @@ -208,4 +208,8 @@ public class TypeInferenceTest extends GroovyResolveTestCase { public void testReturnTypeFromMethodClosure() { assertTypeEquals("java.lang.String","A.groovy"); } + + public void testNoSOF() { + assertTypeEquals("java.lang.Object", "A.groovy"); + } } diff --git a/plugins/groovy/testdata/resolve/inference/noSOF/A.groovy b/plugins/groovy/testdata/resolve/inference/noSOF/A.groovy new file mode 100644 index 000000000000..0d08be6c4ed2 --- /dev/null +++ b/plugins/groovy/testdata/resolve/inference/noSOF/A.groovy @@ -0,0 +1,10 @@ +class Abc3 { + Abc3 foo(){} + def getAt(T t) { + def ab= foo() + throw ab[2] + } +} + +def aa = new Abc3().getAt() +print aa \ No newline at end of file