diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java index d1d663dbf9fa..29eb4bddd0c1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionContributor.java @@ -36,13 +36,8 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Consumer; import com.intellij.util.PairConsumer; import com.intellij.util.ProcessingContext; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.hash.HashMap; -import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.GroovyBundle; -import org.jetbrains.plugins.groovy.GroovyIcons; -import org.jetbrains.plugins.groovy.lang.completion.handlers.NamedArgumentInsertHandler; import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; import org.jetbrains.plugins.groovy.lang.lexer.TokenSets; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; @@ -56,29 +51,23 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgument import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrConstructorCall; 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.expressions.path.GrCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; 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.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; -import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.processors.CompletionProcessor; import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor; -import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; import static com.intellij.patterns.PlatformPatterns.psiElement; import static com.intellij.patterns.PsiJavaPatterns.elementType; @@ -170,78 +159,6 @@ public class GroovyCompletionContributor extends CompletionContributor { } }; - private static final CompletionProvider MAP_ARGUMENT_COMPLETION_PROVIDER = - new CompletionProvider() { - @Override - protected void addCompletions(@NotNull CompletionParameters parameters, - ProcessingContext context, - @NotNull CompletionResultSet result) { - final GrArgumentList argumentList; - - PsiElement parent = parameters.getPosition().getParent(); - if (parent instanceof GrReferenceExpression) { - if (((GrReferenceExpression)parent).getQualifier() != null) return; - argumentList = (GrArgumentList)parent.getParent(); - } - else { - argumentList = (GrArgumentList)parent.getParent().getParent(); - } - - final GrCall call = (GrCall)argumentList.getParent(); - List results = new ArrayList(); - //constructor call - if (call instanceof GrConstructorCall) { - GrConstructorCall constructorCall = (GrConstructorCall)call; - ContainerUtil.addAll(results, constructorCall.multiResolveConstructor()); - ContainerUtil.addAll(results, constructorCall.multiResolveClass()); - } - else if (call instanceof GrCallExpression) { - GrCallExpression constructorCall = (GrCallExpression)call; - ContainerUtil.addAll(results, constructorCall.getCallVariants(null)); - final PsiType type = ((GrCallExpression)call).getType(); - if (type instanceof PsiClassType) { - final PsiClass psiClass = ((PsiClassType)type).resolve(); - results.add(new GroovyResolveResultImpl(psiClass, true)); - } - } - - Set usedClasses = new HashSet(); - Set usedNames = new HashSet(); - for (GrNamedArgument argument : argumentList.getNamedArguments()) { - final GrArgumentLabel label = argument.getLabel(); - if (label != null) { - final String name = label.getName(); - if (name != null) { - usedNames.add(name); - } - } - } - - for (GroovyResolveResult resolveResult : results) { - PsiElement element = resolveResult.getElement(); - if (element instanceof PsiMethod) { - final PsiMethod method = (PsiMethod)element; - final PsiClass containingClass = method.getContainingClass(); - if (containingClass != null) { - addPropertiesForClass(result, usedClasses, usedNames, containingClass, call); - } - if (method instanceof GrMethod) { - for (String parameter : ((GrMethod)method).getNamedParametersArray()) { - if (!usedNames.contains(parameter)) { - final LookupElementBuilder lookup = - LookupElementBuilder.create(parameter).setIcon(GroovyIcons.DYNAMIC).setInsertHandler(NamedArgumentInsertHandler.INSTANCE); - result.addElement(lookup); - } - } - } - } - else if (element instanceof PsiClass) { - addPropertiesForClass(result, usedClasses, usedNames, (PsiClass)element, call); - } - } - } - }; - private static final PsiElementPattern.Capture STATEMENT_START = psiElement(GroovyElementTypes.mIDENT).andOr( psiElement().afterLeaf(StandardPatterns.or( @@ -374,8 +291,8 @@ public class GroovyCompletionContributor extends CompletionContributor { } }); - extend(CompletionType.BASIC, IN_ARGUMENT_LIST_OF_CALL, MAP_ARGUMENT_COMPLETION_PROVIDER); - extend(CompletionType.BASIC, IN_MAP_KEY_ARGUMENT_LIST_OF_CALL, MAP_ARGUMENT_COMPLETION_PROVIDER); + extend(CompletionType.BASIC, IN_ARGUMENT_LIST_OF_CALL, new MapArgumentCompletionProvider()); + extend(CompletionType.BASIC, IN_MAP_KEY_ARGUMENT_LIST_OF_CALL, new MapArgumentCompletionProvider()); // class name stuff @@ -616,62 +533,6 @@ public class GroovyCompletionContributor extends CompletionContributor { return processor; } - private static void addPropertiesForClass(CompletionResultSet result, - Set usedClasses, - Set usedNames, - PsiClass containingClass, - GrCall call) { - if (usedClasses.contains(containingClass)) return; - usedClasses.add(containingClass); - final PsiClass eventListener = - JavaPsiFacade.getInstance(call.getProject()).findClass("java.util.EventListener", call.getResolveScope()); - Map writableProperties = new HashMap(); - for (PsiMethod method : containingClass.getAllMethods()) { - if (GroovyPropertyUtils.isSimplePropertySetter(method)) { - if (PsiUtil.isStaticsOK(method, call)) { - final String name = GroovyPropertyUtils.getPropertyNameBySetter(method); - if (name != null && !writableProperties.containsKey(name)) { - writableProperties.put(name, method); - } - } - } - else if (eventListener != null) { - consumeListenerProperties(result, usedNames, method, eventListener); - } - } - - for (String name : writableProperties.keySet()) { - if (usedNames.contains(name)) continue; - usedNames.add(name); - final LookupElementBuilder builder = - LookupElementBuilder.create(writableProperties.get(name), name).setIcon(GroovyIcons.PROPERTY) - .setInsertHandler(NamedArgumentInsertHandler.INSTANCE); - result.addElement(builder); - } - } - - private static void consumeListenerProperties(CompletionResultSet result, - Set usedNames, PsiMethod method, PsiClass eventListenerClass) { - if (method.getName().startsWith("add") && method.getParameterList().getParametersCount() == 1) { - final PsiParameter parameter = method.getParameterList().getParameters()[0]; - final PsiType type = parameter.getType(); - if (type instanceof PsiClassType) { - final PsiClassType classType = (PsiClassType)type; - final PsiClass listenerClass = classType.resolve(); - if (listenerClass != null) { - final PsiMethod[] listenerMethods = listenerClass.getMethods(); - if (InheritanceUtil.isInheritorOrSelf(listenerClass, eventListenerClass, true)) { - for (PsiMethod listenerMethod : listenerMethods) { - final String name = listenerMethod.getName(); - usedNames.add(name); - result.addElement(LookupElementBuilder.create(name).setIcon(GroovyIcons.PROPERTY).setInsertHandler(NamedArgumentInsertHandler.INSTANCE)); - } - } - } - } - } - } - public void beforeCompletion(@NotNull final CompletionInitializationContext context) { if (context.getCompletionType() == CompletionType.BASIC && context.getFile() instanceof GroovyFile) { if (semicolonNeeded(context)) { @@ -729,5 +590,4 @@ public class GroovyCompletionContributor extends CompletionContributor { } return true; } - } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java new file mode 100644 index 000000000000..b804471b5b2a --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/MapArgumentCompletionProvider.java @@ -0,0 +1,177 @@ +/* + * Copyright 2000-2011 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.completion; + +import com.intellij.codeInsight.completion.CompletionParameters; +import com.intellij.codeInsight.completion.CompletionProvider; +import com.intellij.codeInsight.completion.CompletionResultSet; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.psi.*; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.util.ProcessingContext; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.hash.HashMap; +import com.intellij.util.containers.hash.HashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.GroovyIcons; +import org.jetbrains.plugins.groovy.lang.completion.handlers.NamedArgumentInsertHandler; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrConstructorCall; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** +* @author peter +*/ +class MapArgumentCompletionProvider extends CompletionProvider { + @Override + protected void addCompletions(@NotNull CompletionParameters parameters, + ProcessingContext context, + @NotNull CompletionResultSet result) { + final GrArgumentList argumentList; + + PsiElement parent = parameters.getPosition().getParent(); + if (parent instanceof GrReferenceExpression) { + if (((GrReferenceExpression)parent).getQualifier() != null) return; + argumentList = (GrArgumentList)parent.getParent(); + } + else { + argumentList = (GrArgumentList)parent.getParent().getParent(); + } + + final GrCall call = (GrCall)argumentList.getParent(); + List results = new ArrayList(); + //constructor call + if (call instanceof GrConstructorCall) { + GrConstructorCall constructorCall = (GrConstructorCall)call; + ContainerUtil.addAll(results, constructorCall.multiResolveConstructor()); + ContainerUtil.addAll(results, constructorCall.multiResolveClass()); + } + else if (call instanceof GrCallExpression) { + GrCallExpression constructorCall = (GrCallExpression)call; + ContainerUtil.addAll(results, constructorCall.getCallVariants(null)); + final PsiType type = ((GrCallExpression)call).getType(); + if (type instanceof PsiClassType) { + final PsiClass psiClass = ((PsiClassType)type).resolve(); + results.add(new GroovyResolveResultImpl(psiClass, true)); + } + } + + Set usedClasses = new HashSet(); + Set usedNames = new HashSet(); + for (GrNamedArgument argument : argumentList.getNamedArguments()) { + final GrArgumentLabel label = argument.getLabel(); + if (label != null) { + final String name = label.getName(); + if (name != null) { + usedNames.add(name); + } + } + } + + for (GroovyResolveResult resolveResult : results) { + PsiElement element = resolveResult.getElement(); + if (element instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)element; + final PsiClass containingClass = method.getContainingClass(); + if (containingClass != null) { + addPropertiesForClass(result, usedClasses, usedNames, containingClass, call); + } + if (method instanceof GrMethod) { + for (String parameter : ((GrMethod)method).getNamedParametersArray()) { + if (!usedNames.contains(parameter)) { + final LookupElementBuilder lookup = + LookupElementBuilder.create(parameter).setIcon(GroovyIcons.DYNAMIC).setInsertHandler(NamedArgumentInsertHandler.INSTANCE); + result.addElement(lookup); + } + } + } + } + else if (element instanceof PsiClass) { + addPropertiesForClass(result, usedClasses, usedNames, (PsiClass)element, call); + } + } + } + + private static void addPropertiesForClass(CompletionResultSet result, + Set usedClasses, + Set usedNames, + PsiClass containingClass, + GrCall call) { + if (usedClasses.contains(containingClass)) return; + usedClasses.add(containingClass); + final PsiClass eventListener = + JavaPsiFacade.getInstance(call.getProject()).findClass("java.util.EventListener", call.getResolveScope()); + Map writableProperties = new HashMap(); + for (PsiMethod method : containingClass.getAllMethods()) { + if (GroovyPropertyUtils.isSimplePropertySetter(method)) { + if (PsiUtil.isStaticsOK(method, call)) { + final String name = GroovyPropertyUtils.getPropertyNameBySetter(method); + if (name != null && !writableProperties.containsKey(name)) { + writableProperties.put(name, method); + } + } + } + else if (eventListener != null) { + consumeListenerProperties(result, usedNames, method, eventListener); + } + } + + for (String name : writableProperties.keySet()) { + if (usedNames.contains(name)) continue; + usedNames.add(name); + final LookupElementBuilder builder = + LookupElementBuilder.create(writableProperties.get(name), name).setIcon(GroovyIcons.PROPERTY) + .setInsertHandler(NamedArgumentInsertHandler.INSTANCE); + result.addElement(builder); + } + } + + private static void consumeListenerProperties(CompletionResultSet result, + Set usedNames, PsiMethod method, PsiClass eventListenerClass) { + if (method.getName().startsWith("add") && method.getParameterList().getParametersCount() == 1) { + final PsiParameter parameter = method.getParameterList().getParameters()[0]; + final PsiType type = parameter.getType(); + if (type instanceof PsiClassType) { + final PsiClassType classType = (PsiClassType)type; + final PsiClass listenerClass = classType.resolve(); + if (listenerClass != null) { + final PsiMethod[] listenerMethods = listenerClass.getMethods(); + if (InheritanceUtil.isInheritorOrSelf(listenerClass, eventListenerClass, true)) { + for (PsiMethod listenerMethod : listenerMethods) { + final String name = listenerMethod.getName(); + usedNames.add(name); + result.addElement(LookupElementBuilder.create(name).setIcon(GroovyIcons.PROPERTY).setInsertHandler(NamedArgumentInsertHandler.INSTANCE)); + } + } + } + } + } + } +}