From 33a37e4acaefa3d9582c3e6c0e76f07cba58e628 Mon Sep 17 00:00:00 2001 From: Max Medvedev Date: Tue, 16 Apr 2013 16:23:22 +0400 Subject: [PATCH] IDEA-104739 completion for binding variables --- .../CompleteReferenceExpression.java | 38 +++++++++++++++++++ .../psi/impl/synthetic/GrBindingVariable.java | 6 +++ .../completion/GroovyCompletionTest.groovy | 37 ++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java index 689ec76325b2..1faac51b0ee3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java @@ -36,7 +36,9 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionUtil; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation; @@ -44,6 +46,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation. import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; 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.expressions.GrAssignmentExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; @@ -53,6 +56,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrRe import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager; import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrBindingVariable; import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.ClosureParameterEnhancer; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ClosureMissingMethodContributor; @@ -128,6 +132,8 @@ public class CompleteReferenceExpression { if (qualifier != null) { getVariantsFromQualifier(refExpr, processor, qualifier); } + + getBindings(refExpr, processor); } else { if (refExpr.getDotTokenType() != GroovyTokenTypes.mSPREAD_DOT) { @@ -145,6 +151,38 @@ public class CompleteReferenceExpression { ResolveUtil.processCategoryMembers(refExpr, processor, ResolveState.initial()); } + private static void getBindings(final GrReferenceExpression refExpr, final CompleteReferenceProcessor processor) { + final PsiClass containingClass = PsiTreeUtil.getParentOfType(refExpr, PsiClass.class); + if (containingClass != null) return; + + final PsiFile file = refExpr.getContainingFile(); + if (file instanceof GroovyFile) { + ((GroovyFile)file).accept(new GroovyRecursiveElementVisitor() { + @Override + public void visitAssignmentExpression(GrAssignmentExpression expression) { + super.visitAssignmentExpression(expression); + + final GrExpression value = expression.getLValue(); + if (value instanceof GrReferenceExpression && !((GrReferenceExpression)value).isQualified()) { + final PsiElement resolved = ((GrReferenceExpression)value).resolve(); + if (resolved instanceof GrBindingVariable) { + processor.execute(resolved, ResolveState.initial()); + } + else if (resolved == null) { + processor.execute(new GrBindingVariable((GroovyFile)file, ((GrReferenceExpression)value).getReferenceName(), true), + ResolveState.initial()); + } + } + } + + @Override + public void visitTypeDefinition(GrTypeDefinition typeDefinition) { + //don't go into classes + } + }); + } + } + private static void getVariantsFromQualifierForSpreadOperator(GrReferenceExpression refExpr, ResolverProcessor processor, GrExpression qualifier) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrBindingVariable.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrBindingVariable.java index 9e3ddcedfba4..967cab886e0d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrBindingVariable.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/synthetic/GrBindingVariable.java @@ -28,6 +28,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; 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.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import javax.swing.*; @@ -121,6 +122,11 @@ public class GrBindingVariable extends GrLightVariable implements GrVariable { super.visitAssignmentExpression(expression); } + @Override + public void visitTypeDefinition(GrTypeDefinition typeDefinition) { + //don't go inside type definitions + } + @Override public void visitElement(GroovyPsiElement element) { if (myHasWriteAccess == null) { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy index 137ff6fdf5a6..1450e80c4dbc 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy @@ -1734,4 +1734,41 @@ class Inheritor extends Base { doVariantableTest('Inheritor.fo','', CompletionType.BASIC, CompletionResult.equal, 'foo', 'forName', 'forName') } + + void testBinding1() { + doCompletionTest('''\ +aaa = 5 +print aa +''', '''\ +aaa = 5 +print aaa +''', CompletionType.BASIC) + } + + void testBinding2() { + doCompletionTest('''\ +def foo() { + aaa = 5 +} +print aa +''', '''\ +def foo() { + aaa = 5 +} +print aaa +''', CompletionType.BASIC) + } + + + void testBinding3() { + doVariantableTest('''\ +def x() { + aaa = 5 +} + +aaaa = 6 +print aa +''', CompletionType.BASIC, 'aaa', 'aaaa') + } + } \ No newline at end of file