merge
[idea/community.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / lang / resolve / ResolveUtil.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.jetbrains.plugins.groovy.lang.resolve;
18
19 import com.intellij.openapi.project.Project;
20 import com.intellij.openapi.roots.ProjectRootManager;
21 import com.intellij.openapi.util.Key;
22 import com.intellij.openapi.util.Pair;
23 import com.intellij.openapi.util.Ref;
24 import com.intellij.psi.*;
25 import com.intellij.psi.scope.JavaScopeProcessorEvent;
26 import com.intellij.psi.scope.NameHint;
27 import com.intellij.psi.scope.PsiScopeProcessor;
28 import com.intellij.psi.util.*;
29 import org.jetbrains.annotations.NotNull;
30 import org.jetbrains.annotations.Nullable;
31 import org.jetbrains.plugins.groovy.dsl.GroovyDslFileIndex;
32 import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
33 import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
34 import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
35 import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
36 import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
37 import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
38 import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
39 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
40 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
41 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
42 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression;
43 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
44 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
45 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody;
46 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
47 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
48 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
49 import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
50 import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
51 import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassResolverProcessor;
52 import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor;
53 import org.jetbrains.plugins.groovy.lang.resolve.processors.PropertyResolverProcessor;
54 import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
55
56 import java.util.*;
57 import java.util.concurrent.ConcurrentHashMap;
58
59 /**
60  * @author ven
61  */
62 @SuppressWarnings({"StringBufferReplaceableByString"})
63 public class ResolveUtil {
64   public static final PsiScopeProcessor.Event DECLARATION_SCOPE_PASSED = new PsiScopeProcessor.Event() {};
65
66   private ResolveUtil() {
67   }
68
69   public static boolean treeWalkUp(@NotNull GroovyPsiElement place, PsiScopeProcessor processor, boolean processNonCodeMethods) {
70     PsiElement lastParent = null;
71     PsiElement run = place;
72
73     final Project project = place.getProject();
74     PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
75
76     while (run != null) {
77       if (!run.processDeclarations(processor, ResolveState.initial(), lastParent, place)) return false;
78       if (processNonCodeMethods) {
79         if (run instanceof GrTypeDefinition) {
80           processNonCodeMethods(factory.createType(((GrTypeDefinition)run)), processor, place);
81         }
82         else if ((run instanceof GroovyFileBase) && ((GroovyFileBase)run).isScript()) {
83           final PsiClass psiClass = ((GroovyFileBase)run).getScriptClass();
84           if (psiClass != null) {
85             processNonCodeMethods(factory.createType(psiClass), processor, place);
86           }
87         }
88       }
89       lastParent = run;
90       run = run.getContext();
91       processor.handleEvent(JavaScopeProcessorEvent.CHANGE_LEVEL, null);
92     }
93
94     return true;
95   }
96
97   public static boolean processChildren(PsiElement element,
98                                         PsiScopeProcessor processor,
99                                         ResolveState substitutor,
100                                         PsiElement lastParent,
101                                         PsiElement place) {
102     PsiElement run = lastParent == null ? element.getLastChild() : lastParent.getPrevSibling();
103     while (run != null) {
104       if (!run.processDeclarations(processor, substitutor, null, place)) return false;
105       run = run.getPrevSibling();
106     }
107
108     return true;
109   }
110
111   @Nullable
112   public static String getNameHint(PsiScopeProcessor processor) {
113     NameHint nameHint = processor.getHint(NameHint.KEY);
114     if (nameHint == null) {
115       return null;
116     }
117
118     return nameHint.getName(ResolveState.initial());
119   }
120
121   public static boolean processElement(PsiScopeProcessor processor, PsiNamedElement namedElement, ResolveState state) {
122     NameHint nameHint = processor.getHint(NameHint.KEY);
123     //todo [DIANA] look more carefully
124     String name = nameHint == null ? null : nameHint.getName(state);
125     if (name == null || name.equals(namedElement.getName())) {
126       return processor.execute(namedElement, state);
127     }
128
129     return true;
130   }
131
132   public static boolean processAllDeclarations(@NotNull PsiType type,
133                                                @NotNull PsiScopeProcessor processor,
134                                                @NotNull ResolveState state,
135                                                @NotNull GroovyPsiElement place) {
136     if (type instanceof PsiClassType) {
137       final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)type).resolveGenerics();
138       final PsiClass psiClass = resolveResult.getElement();
139       if (psiClass != null) {
140         if (!psiClass.processDeclarations(processor, state, null, place)) return false;
141       }
142     }
143     return processNonCodeMethods(type, processor, place, state);
144   }
145
146   public static boolean processNonCodeMethods(PsiType type,
147                                               PsiScopeProcessor processor,
148                                               GroovyPsiElement place) {
149     return processNonCodeMethods(type, processor, place, ResolveState.initial());
150   }
151
152   public static boolean processNonCodeMethods(PsiType type,
153                                               PsiScopeProcessor processor,
154                                               GroovyPsiElement place,
155                                               ResolveState state) {
156     if (!NonCodeMembersContributor.runContributors(type, processor, place, state)) {
157       return false;
158     }
159
160     if (!GroovyDslFileIndex.processExecutors(type, place, processor, state)) {
161       return false;
162     }
163
164     return true;
165   }
166
167   private static final Key<PsiType> COMPARABLE = Key.create(CommonClassNames.JAVA_LANG_COMPARABLE);
168   private static final Key<PsiType> SERIALIZABLE = Key.create(CommonClassNames.JAVA_IO_SERIALIZABLE);
169   private static final Key<PsiType> STRING = Key.create(CommonClassNames.JAVA_LANG_STRING);
170
171   private static void collectSuperTypes(PsiType type, Map<String, PsiType> visited, Project project) {
172     String qName = rawCanonicalText(type);
173
174     if (visited.put(qName, type) != null) {
175       return;
176     }
177
178     final PsiType[] superTypes = type.getSuperTypes();
179     for (PsiType superType : superTypes) {
180       collectSuperTypes(TypeConversionUtil.erasure(superType), visited, project);
181     }
182
183     if (type instanceof PsiArrayType && superTypes.length == 0) {
184       PsiType comparable = createTypeFromText(project, COMPARABLE, CommonClassNames.JAVA_LANG_COMPARABLE);
185       PsiType serializable = createTypeFromText(project, SERIALIZABLE, CommonClassNames.JAVA_IO_SERIALIZABLE);
186       collectSuperTypes(comparable, visited, project);
187       collectSuperTypes(serializable, visited, project);
188     }
189
190     if (GroovyCommonClassNames.GROOVY_LANG_GSTRING.equals(qName)) {
191       collectSuperTypes(createTypeFromText(project, STRING, CommonClassNames.JAVA_LANG_STRING), visited, project);
192     }
193
194   }
195
196   public static PsiType createTypeFromText(Project project, Key<PsiType> key, String text) {
197     final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
198     PsiType type = project.getUserData(key);
199     if (type == null) {
200       type = factory.createTypeFromText(text, null);
201       project.putUserData(key, type);
202     }
203     return type;
204   }
205
206   public static Map<String, PsiType> getAllSuperTypes(@NotNull PsiType base, final Project project) {
207     final Map<String, Map<String, PsiType>> cache =
208       CachedValuesManager.getManager(project).getCachedValue(project, new CachedValueProvider<Map<String, Map<String, PsiType>>>() {
209         @Override
210         public Result<Map<String, Map<String, PsiType>>> compute() {
211           final Map<String, Map<String, PsiType>> result = new ConcurrentHashMap<String, Map<String, PsiType>>();
212           return Result.create(result, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(project));
213         }
214       });
215
216     final PsiClass cls = PsiUtil.resolveClassInType(base);
217     //noinspection ConstantConditions
218     String key;
219     if (cls instanceof PsiTypeParameter) {
220       final PsiClass superClass = cls.getSuperClass();
221       key = cls.getName() + (superClass == null ? CommonClassNames.JAVA_LANG_OBJECT : superClass.getName());
222     }
223     else {
224       key = TypeConversionUtil.erasure(base).getCanonicalText();
225     }
226     if (key == null) key = "";
227     Map<String, PsiType> result = cache.get(key);
228     if (result == null) {
229       result = new HashMap<String, PsiType>();
230       collectSuperTypes(base, result, project);
231       cache.put(key, result);
232     }
233     return result;
234   }
235
236   public static boolean isInheritor(PsiType type, @NotNull String baseClass, Project project) {
237     return getAllSuperTypes(type, project).keySet().contains(baseClass);
238   }
239
240
241   @NotNull
242   private static String rawCanonicalText(@NotNull PsiType type) {
243     final String result = type.getCanonicalText();
244     if (result == null) return "";
245     final int i = result.indexOf('<');
246     if (i > 0) return result.substring(0, i);
247     return result;
248   }
249
250   @Nullable
251   public static PsiType getListTypeForSpreadOperator(GrReferenceExpression refExpr, PsiType componentType) {
252     PsiClass clazz = JavaPsiFacade.getInstance(refExpr.getManager().getProject())
253       .findClass(CommonClassNames.JAVA_UTIL_LIST, refExpr.getResolveScope());
254     if (clazz != null) {
255       PsiTypeParameter[] typeParameters = clazz.getTypeParameters();
256       if (typeParameters.length == 1) {
257         PsiSubstitutor substitutor = PsiSubstitutor.EMPTY.put(typeParameters[0], componentType);
258         return JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory().createType(clazz, substitutor);
259       }
260     }
261
262     return null;
263   }
264
265   public static GroovyPsiElement resolveProperty(GroovyPsiElement place, String name) {
266     PropertyResolverProcessor processor = new PropertyResolverProcessor(name, place);
267     return resolveExistingElement(place, processor, GrVariable.class, GrReferenceExpression.class);
268   }
269
270   @Nullable
271   public static PsiClass resolveClass(GroovyPsiElement place, String name) {
272     ClassResolverProcessor processor = new ClassResolverProcessor(name, place);
273     return resolveExistingElement(place, processor, PsiClass.class);
274   }
275
276   @Nullable
277   public static <T> T resolveExistingElement(GroovyPsiElement place, ResolverProcessor processor, Class<? extends T>... classes) {
278     treeWalkUp(place, processor, true);
279     final GroovyResolveResult[] candidates = processor.getCandidates();
280     for (GroovyResolveResult candidate : candidates) {
281       final PsiElement element = candidate.getElement();
282       if (element == place) continue;
283       for (Class<? extends T> clazz : classes) {
284         if (clazz.isInstance(element)) //noinspection unchecked
285           return (T)element;
286       }
287     }
288
289     return null;
290   }
291
292   @NotNull
293   public static Pair<GrStatement, GrLabeledStatement> resolveLabelTargets(@Nullable String labelName,
294                                                                           @Nullable PsiElement element,
295                                                                           boolean isBreak) {
296     if (element == null) return new Pair<GrStatement, GrLabeledStatement>(null, null);
297
298     if (labelName == null) {
299       do {
300         element = element.getParent();
301         if (element == null || element instanceof GrClosableBlock || element instanceof GrMember || element instanceof GroovyFile) {
302           return new Pair<GrStatement, GrLabeledStatement>(null, null);
303         }
304       }
305       while (!(element instanceof GrLoopStatement) && !(isBreak && element instanceof GrSwitchStatement));
306       return new Pair<GrStatement, GrLabeledStatement>(((GrStatement)element), null);
307     }
308
309     GrStatement statement = null;
310     do {
311       PsiElement last = element;
312       element = element.getParent();
313       if (element == null || element instanceof GrMember || element instanceof GroovyFile) break;
314       if (element instanceof GrStatement && !(element instanceof GrClosableBlock)) {
315         statement = (GrStatement)element;
316       }
317       PsiElement sibling = element;
318       while (sibling != null) {
319         final GrLabeledStatement labelStatement = findLabelStatementIn(sibling, last, labelName);
320         if (labelStatement != null) {
321           return new Pair<GrStatement, GrLabeledStatement>(statement, labelStatement);
322         }
323         sibling = sibling.getPrevSibling();
324       }
325       if (element instanceof GrClosableBlock) break;
326     }
327     while (true);
328     return new Pair<GrStatement, GrLabeledStatement>(null, null);
329   }
330
331   private static boolean isApplicableLabelStatement(PsiElement element, String labelName) {
332     return ((element instanceof GrLabeledStatement && labelName.equals(((GrLabeledStatement)element).getLabelName())));
333   }
334
335   @Nullable
336   private static GrLabeledStatement findLabelStatementIn(PsiElement element, PsiElement lastChild, String labelName) {
337     if (isApplicableLabelStatement(element, labelName)) {
338       return (GrLabeledStatement)element;
339     }
340     for (PsiElement child = element.getFirstChild(); child != null && child != lastChild; child = child.getNextSibling()) {
341       final GrLabeledStatement statement = findLabelStatementIn(child, child, labelName);
342       if (statement != null) return statement;
343     }
344     return null;
345   }
346
347   @Nullable
348   public static GrLabeledStatement resolveLabeledStatement(@Nullable String labelName, @Nullable PsiElement element, boolean isBreak) {
349     return resolveLabelTargets(labelName, element, isBreak).second;
350   }
351
352   @Nullable
353   public static GrStatement resolveLabelTargetStatement(@Nullable String labelName, @Nullable PsiElement element, boolean isBreak) {
354     return resolveLabelTargets(labelName, element, isBreak).first;
355   }
356
357   public static boolean processCategoryMembers(PsiElement place, ResolverProcessor processor) {
358     PsiElement prev = null;
359     Ref<Boolean> result = new Ref<Boolean>(null);
360     while (place != null) {
361       if (place instanceof GrMember) break;
362       if (categoryIteration(place, processor, prev, result)) return result.get();
363
364       prev = place;
365       place = place.getContext();
366     }
367
368     return true;
369   }
370
371   private static boolean categoryIteration(PsiElement place, ResolverProcessor processor, PsiElement prev, Ref<Boolean> result) {
372     if (!(place instanceof GrMethodCall)) return false;
373
374     final GrMethodCall call = (GrMethodCall)place;
375     final GrExpression invoked = call.getInvokedExpression();
376     if (!(invoked instanceof GrReferenceExpression) || !"use".equals(((GrReferenceExpression)invoked).getReferenceName())) return false;
377
378     final GrClosableBlock[] closures = call.getClosureArguments();
379     if (closures.length != 1 || !closures[0].equals(prev)) return false;
380
381     if (!(call.resolveMethod() instanceof GrGdkMethod)) return false;
382
383     final GrArgumentList argList = call.getArgumentList();
384     if (argList == null) return false;
385
386     result.set(Boolean.TRUE);
387     final GrExpression[] args = argList.getExpressionArguments();
388     for (GrExpression arg : args) {
389       if (arg instanceof GrReferenceExpression) {
390         final PsiElement resolved = ((GrReferenceExpression)arg).resolve();
391         if (resolved instanceof PsiClass) {
392           if (!resolved.processDeclarations(processor, ResolveState.initial().put(ResolverProcessor.RESOLVE_CONTEXT, call), null, place)) {
393             result.set(Boolean.FALSE);
394           }
395         }
396       }
397     }
398     return true;
399   }
400
401   public static PsiElement[] mapToElements(GroovyResolveResult[] candidates) {
402     PsiElement[] elements = new PsiElement[candidates.length];
403     for (int i = 0; i < elements.length; i++) {
404       elements[i] = candidates[i].getElement();
405     }
406
407     return elements;
408   }
409
410   public static GroovyResolveResult[] filterSameSignatureCandidates(Collection<GroovyResolveResult> candidates, int argumentCount) {
411     GroovyResolveResult[] array = candidates.toArray(new GroovyResolveResult[candidates.size()]);
412     if (array.length == 1) return array;
413
414     List<GroovyResolveResult> result = new ArrayList<GroovyResolveResult>();
415     result.add(array[0]);
416
417     Outer:
418     for (int i = 1; i < array.length; i++) {
419       PsiElement currentElement = array[i].getElement();
420       if (currentElement instanceof PsiMethod) {
421         PsiMethod currentMethod = (PsiMethod)currentElement;
422         for (Iterator<GroovyResolveResult> iterator = result.iterator(); iterator.hasNext();) {
423           final GroovyResolveResult otherResolveResult = iterator.next();
424           PsiElement element = otherResolveResult.getElement();
425           if (element instanceof PsiMethod) {
426             PsiMethod method = (PsiMethod)element;
427             if (dominated(currentMethod, array[i].getSubstitutor(), method, otherResolveResult.getSubstitutor())) {
428               continue Outer;
429             }
430             else if (dominated(method, otherResolveResult.getSubstitutor(), currentMethod, array[i].getSubstitutor())) {
431               iterator.remove();
432             }
433           }
434         }
435       }
436
437       result.add(array[i]);
438     }
439
440     return result.toArray(new GroovyResolveResult[result.size()]);
441   }
442
443   public static boolean dominated(PsiMethod method1,
444                                   PsiSubstitutor substitutor1,
445                                   PsiMethod method2,
446                                   PsiSubstitutor substitutor2) {  //method1 has more general parameter types then method2
447     if (!method1.getName().equals(method2.getName())) return false;
448
449     PsiParameter[] params1 = method1.getParameterList().getParameters();
450     PsiParameter[] params2 = method2.getParameterList().getParameters();
451
452     if (params1.length != params2.length) return false;
453
454     for (int i = 0; i < params2.length; i++) {
455       PsiType type1 = substitutor1.substitute(params1[i].getType());
456       PsiType type2 = substitutor2.substitute(params2[i].getType());
457       if (!type1.equals(type2)) return false;
458     }
459
460     return true;
461   }
462
463   public static GroovyResolveResult[] getCallVariants(GroovyPsiElement place) {
464     final PsiElement parent = place.getParent();
465     GroovyResolveResult[] variants = GroovyResolveResult.EMPTY_ARRAY;
466     if (parent instanceof GrCallExpression) {
467       variants = ((GrCallExpression)parent).getCallVariants(place instanceof GrExpression ? (GrExpression)place : null);
468     }
469     else if (parent instanceof GrConstructorInvocation) {
470       final PsiClass clazz = ((GrConstructorInvocation)parent).getDelegatedClass();
471       if (clazz != null) {
472         final PsiMethod[] constructors = clazz.getConstructors();
473         variants = getConstructorResolveResult(constructors, place);
474       }
475     }
476     else if (parent instanceof GrAnonymousClassDefinition) {
477       final PsiElement element = ((GrAnonymousClassDefinition)parent).getBaseClassReferenceGroovy().resolve();
478       if (element instanceof PsiClass) {
479         final PsiMethod[] constructors = ((PsiClass)element).getConstructors();
480         variants = getConstructorResolveResult(constructors, place);
481       }
482     }
483     else if (place instanceof GrReferenceExpression) {
484       variants = ((GrReferenceExpression)place).getSameNameVariants();
485     }
486     return variants;
487   }
488
489   public static GroovyResolveResult[] getConstructorResolveResult(PsiMethod[] constructors, PsiElement place) {
490     GroovyResolveResult[] variants = new GroovyResolveResult[constructors.length];
491     for (int i = 0; i < constructors.length; i++) {
492       final boolean isAccessible = PsiUtil.isAccessible(constructors[i], place, null);
493       variants[i] = new GroovyResolveResultImpl(constructors[i], isAccessible);
494     }
495     return variants;
496   }
497
498   public static GroovyResolveResult[] getNonCodeConstructors(PsiClass psiClass, GroovyPsiElement place, PsiSubstitutor substitutor) {
499     final PsiClassType qualifierType = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass);
500     final MethodResolverProcessor processor = new MethodResolverProcessor(psiClass.getName(), place, true, null, null, PsiType.EMPTY_ARRAY);
501     NonCodeMembersContributor
502       .runContributors(qualifierType, processor, place, ResolveState.initial().put(PsiSubstitutor.KEY, substitutor));
503     return processor.getCandidates();
504   }
505
506   public static PsiMethod[] getAllClassConstructors(PsiClass psiClass, GroovyPsiElement place, PsiSubstitutor substitutor) {
507     final PsiMethod[] realConstructors = psiClass.getConstructors();
508     final GroovyResolveResult[] nonCodeConstructors = getNonCodeConstructors(psiClass, place, substitutor);
509     PsiMethod[] constructors = new PsiMethod[realConstructors.length + nonCodeConstructors.length];
510     System.arraycopy(realConstructors, 0, constructors, 0, realConstructors.length);
511     for (int i = 0; i < nonCodeConstructors.length; i++) {
512       GroovyResolveResult nonCodeConstructor = nonCodeConstructors[i];
513       final PsiElement element = nonCodeConstructor.getElement();
514       if (element instanceof PsiMethod) {
515         constructors[i + realConstructors.length] = (PsiMethod)element;
516       }
517     }
518     return constructors;
519   }
520
521   public static boolean isInUseScope(GroovyResolveResult resolveResult) {
522     return resolveResult != null && isInUseScope(resolveResult.getCurrentFileResolveContext());
523   }
524
525   public static boolean isInUseScope(PsiElement context) {
526     if (context instanceof GrMethodCall) {
527       final GrExpression expression = ((GrMethodCall)context).getInvokedExpression();
528       if (expression instanceof GrReferenceExpression) {
529         final PsiElement resolved = ((GrReferenceExpression)expression).resolve();
530         if (resolved instanceof GrGdkMethod && "use".equals(((GrGdkMethod)resolved).getStaticMethod().getName())) {
531           return true;
532         }
533       }
534     }
535     return false;
536   }
537
538   public static boolean isInWithContext(GroovyResolveResult resolveResult) {
539     return isInWithContext(resolveResult.getCurrentFileResolveContext());
540   }
541
542   public static boolean isInWithContext(GroovyPsiElement resolveContext) {
543     if (resolveContext instanceof GrExpression) {
544       final PsiElement parent = resolveContext.getParent();
545       if (parent instanceof GrReferenceExpression && ((GrReferenceExpression)parent).getQualifier() == resolveContext) {
546         final PsiElement pparent = parent.getParent();
547         if (pparent instanceof GrMethodCall) {
548           final PsiMethod method = ((GrMethodCall)pparent).resolveMethod();
549           if (method instanceof GrGdkMethod && "with".equals(method.getName())) {
550             return true;
551           }
552         }
553       }
554     }
555     return false;
556   }
557
558   public static boolean referenceIsKeyOfMap(GrReferenceExpression ref) {
559     final GrExpression qualifier = ref.getQualifierExpression();
560     if (qualifier != null) {
561       return InheritanceUtil.isInheritor(qualifier.getType(), CommonClassNames.JAVA_UTIL_MAP);
562     }
563
564     PsiElement place = ref;
565     while (true) {
566       final GrClosableBlock closure =
567         PsiTreeUtil.getParentOfType(place, GrClosableBlock.class, true, GrMethod.class, GroovyFile.class, GrTypeDefinitionBody.class);
568       if (closure == null) break;
569       place = closure;
570       PsiElement clParent = closure.getParent();
571       if (clParent instanceof GrArgumentList) clParent = clParent.getParent();
572       if (!(clParent instanceof GrMethodCall)) continue;
573       final GrExpression expression = ((GrMethodCall)clParent).getInvokedExpression();
574       if (expression instanceof GrReferenceExpression &&
575           "with".equals(((GrReferenceExpression)expression).getReferenceName()) &&
576           ((GrReferenceExpression)expression).resolve() instanceof GrGdkMethod) {
577         final GrExpression withQualifier = ((GrReferenceExpression)expression).getQualifierExpression();
578         if (withQualifier != null) {
579           return InheritanceUtil.isInheritor(withQualifier.getType(), CommonClassNames.JAVA_UTIL_MAP);
580         }
581       }
582     }
583     return false;
584   }
585
586   @NotNull
587   public static GroovyResolveResult[] getMethodCandidates(@NotNull PsiType thisType,
588                                                           @Nullable String methodName,
589                                                           @NotNull GroovyPsiElement place,
590                                                           @Nullable PsiType[] argumentTypes) {
591     if (methodName != null) {
592       MethodResolverProcessor processor =
593         new MethodResolverProcessor(methodName, place, false, thisType, argumentTypes, PsiType.EMPTY_ARRAY);
594       final ResolveState state;
595       if (thisType instanceof PsiClassType) {
596         final PsiClassType classtype = (PsiClassType)thisType;
597         final PsiClassType.ClassResolveResult resolveResult = classtype.resolveGenerics();
598         final PsiClass lClass = resolveResult.getElement();
599         state = ResolveState.initial().put(PsiSubstitutor.KEY, resolveResult.getSubstitutor());
600         if (lClass != null) {
601           lClass.processDeclarations(processor, state, null, place);
602         }
603       }
604       else {
605         state = ResolveState.initial();
606       }
607
608       processNonCodeMethods(thisType, processor, place, state);
609       processCategoryMembers(place, processor);
610       return processor.getCandidates();
611     }
612     return GroovyResolveResult.EMPTY_ARRAY;
613   }
614 }