2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.statements
.typedef
.members
;
18 import com
.intellij
.lang
.ASTNode
;
19 import com
.intellij
.navigation
.ItemPresentation
;
20 import com
.intellij
.psi
.*;
21 import com
.intellij
.psi
.impl
.ElementPresentationUtil
;
22 import com
.intellij
.psi
.impl
.PsiClassImplUtil
;
23 import com
.intellij
.psi
.impl
.PsiSuperMethodImplUtil
;
24 import com
.intellij
.psi
.presentation
.java
.JavaPresentationUtil
;
25 import com
.intellij
.psi
.scope
.PsiScopeProcessor
;
26 import com
.intellij
.psi
.search
.SearchScope
;
27 import com
.intellij
.psi
.stubs
.IStubElementType
;
28 import com
.intellij
.psi
.stubs
.NamedStub
;
29 import com
.intellij
.psi
.util
.MethodSignature
;
30 import com
.intellij
.psi
.util
.MethodSignatureBackedByPsiMethod
;
31 import com
.intellij
.psi
.util
.MethodSignatureUtil
;
32 import com
.intellij
.ui
.RowIcon
;
33 import com
.intellij
.util
.Function
;
34 import com
.intellij
.util
.IncorrectOperationException
;
35 import com
.intellij
.util
.NullableFunction
;
36 import org
.jetbrains
.annotations
.NonNls
;
37 import org
.jetbrains
.annotations
.NotNull
;
38 import org
.jetbrains
.annotations
.Nullable
;
39 import org
.jetbrains
.plugins
.groovy
.GroovyIcons
;
40 import org
.jetbrains
.plugins
.groovy
.lang
.groovydoc
.psi
.api
.GrDocComment
;
41 import org
.jetbrains
.plugins
.groovy
.lang
.groovydoc
.psi
.impl
.GrDocCommentUtil
;
42 import org
.jetbrains
.plugins
.groovy
.lang
.lexer
.TokenSets
;
43 import org
.jetbrains
.plugins
.groovy
.lang
.parser
.GroovyElementTypes
;
44 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.GroovyElementVisitor
;
45 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.GroovyFileBase
;
46 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.auxiliary
.GrThrowsClause
;
47 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.auxiliary
.modifiers
.GrModifierList
;
48 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.GrNamedArgumentSearchVisitor
;
49 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.blocks
.GrCodeBlock
;
50 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.blocks
.GrOpenBlock
;
51 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.params
.GrParameter
;
52 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.params
.GrParameterList
;
53 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.GrTypeDefinitionBody
;
54 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.members
.GrMember
;
55 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.statements
.typedef
.members
.GrMethod
;
56 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.types
.GrTypeElement
;
57 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.types
.GrTypeParameter
;
58 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.api
.types
.GrTypeParameterList
;
59 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.GroovyBaseElementImpl
;
60 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.GroovyFileImpl
;
61 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.GroovyPsiManager
;
62 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.PsiImplUtil
;
63 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.auxiliary
.modifiers
.GrModifierListImpl
;
64 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.impl
.statements
.params
.GrParameterListImpl
;
65 import org
.jetbrains
.plugins
.groovy
.lang
.psi
.util
.PsiUtil
;
66 import org
.jetbrains
.plugins
.groovy
.lang
.resolve
.MethodTypeInferencer
;
67 import org
.jetbrains
.plugins
.groovy
.lang
.resolve
.ResolveUtil
;
75 public abstract class GrMethodBaseImpl
<T
extends NamedStub
> extends GroovyBaseElementImpl
<T
> implements GrMethod
{
77 protected GrMethodBaseImpl(final T stub
, IStubElementType nodeType
) {
78 super(stub
, nodeType
);
81 public GrMethodBaseImpl(final ASTNode node
) {
85 public void accept(GroovyElementVisitor visitor
) {
86 visitor
.visitMethod(this);
89 public int getTextOffset() {
90 return getNameIdentifierGroovy().getTextRange().getStartOffset();
94 public PsiElement
getNameIdentifierGroovy() {
95 return findChildByType(TokenSets
.PROPERTY_NAMES
);
99 public GrOpenBlock
getBlock() {
100 return this.findChildByClass(GrOpenBlock
.class);
103 public void setBlock(GrCodeBlock newBlock
) {
104 ASTNode newNode
= newBlock
.getNode().copyElement();
105 final GrOpenBlock oldBlock
= getBlock();
106 if (oldBlock
== null) {
107 getNode().addChild(newNode
);
110 getNode().replaceChild(oldBlock
.getNode(), newNode
);
113 public GrParameter
[] getParameters() {
114 GrParameterListImpl parameterList
= findChildByClass(GrParameterListImpl
.class);
115 if (parameterList
!= null) {
116 return parameterList
.getParameters();
119 return GrParameter
.EMPTY_ARRAY
;
122 public GrTypeElement
getReturnTypeElementGroovy() {
123 return findChildByClass(GrTypeElement
.class);
127 public PsiType
getDeclaredReturnType() {
128 final GrTypeElement typeElement
= getReturnTypeElementGroovy();
129 if (typeElement
!= null) return typeElement
.getType();
133 public boolean processDeclarations(@NotNull PsiScopeProcessor processor
,
134 @NotNull ResolveState state
,
135 PsiElement lastParent
,
136 @NotNull PsiElement place
) {
137 for (final GrTypeParameter typeParameter
: getTypeParameters()) {
138 if (!ResolveUtil
.processElement(processor
, typeParameter
)) return false;
141 for (final GrParameter parameter
: getParameters()) {
142 if (!ResolveUtil
.processElement(processor
, parameter
)) return false;
145 processor
.handleEvent(ResolveUtil
.DECLARATION_SCOPE_PASSED
, this);
150 public GrMember
[] getMembers() {
151 return new GrMember
[]{this};
154 private static final Function
<GrMethod
, PsiType
> ourTypesCalculator
= new NullableFunction
<GrMethod
, PsiType
>() {
155 public PsiType
fun(GrMethod method
) {
156 PsiType nominal
= getNominalType(method
);
157 if (nominal
!= null && nominal
.equals(PsiType
.VOID
)) return nominal
;
158 PsiType inferred
= getInferredType(method
);
159 if (nominal
== null) {
160 if (inferred
== null) {
161 return PsiType
.getJavaLangObject(PsiManager
.getInstance(method
.getProject()), method
.getResolveScope());
165 if (inferred
!= null && inferred
!= PsiType
.NULL
) {
166 if (nominal
.isAssignableFrom(inferred
)) return inferred
;
172 private PsiType
getNominalType(GrMethod method
) {
173 GrTypeElement element
= method
.getReturnTypeElementGroovy();
174 return element
!= null ? element
.getType() : null;
178 private PsiType
getInferredType(GrMethod method
) {
179 final GrOpenBlock block
= method
.getBlock();
180 if (block
== null) return null;
182 if (GroovyPsiManager
.isTypeBeingInferred(method
)) {
186 return GroovyPsiManager
.inferType(method
, new MethodTypeInferencer(block
));
190 //PsiMethod implementation
192 public PsiType
getReturnType() {
193 return GroovyPsiManager
.getInstance(getProject()).getType(this, ourTypesCalculator
);
197 public Icon
getIcon(int flags
) {
198 RowIcon baseIcon
= createLayeredIcon(GroovyIcons
.METHOD
, ElementPresentationUtil
.getFlags(this, false));
199 return ElementPresentationUtil
.addVisibilityIcon(this, flags
, baseIcon
);
203 public ItemPresentation
getPresentation() {
204 return JavaPresentationUtil
.getMethodPresentation(this);
208 public PsiTypeElement
getReturnTypeElement() {
213 public GrParameterList
getParameterList() {
214 GrParameterList parameterList
= (GrParameterList
)findChildByType(GroovyElementTypes
.PARAMETERS_LIST
);
215 assert parameterList
!= null;
216 return parameterList
;
220 public PsiReferenceList
getThrowsList() {
221 GrThrowsClause clause
= findChildByClass(GrThrowsClause
.class);
222 assert clause
!= null;
227 public PsiCodeBlock
getBody() {
231 public boolean isConstructor() {
235 public boolean isVarArgs() {
236 GrParameter
[] parameters
= getParameters();
237 return parameters
.length
> 0 && parameters
[parameters
.length
- 1].isVarArgs();
241 public MethodSignature
getSignature(@NotNull PsiSubstitutor substitutor
) {
242 return MethodSignatureBackedByPsiMethod
.create(this, substitutor
);
246 public PsiIdentifier
getNameIdentifier() {
247 return PsiUtil
.getJavaNameIdentifier(this);
250 private static void findSuperMethodRecursively(Set
<PsiMethod
> methods
,
253 Set
<PsiClass
> visited
,
254 MethodSignature signature
,
255 @NotNull Set
<MethodSignature
> discoveredSupers
) {
256 if (psiClass
== null) return;
257 if (visited
.contains(psiClass
)) return;
258 visited
.add(psiClass
);
259 PsiClassType
[] superClassTypes
= psiClass
.getSuperTypes();
261 for (PsiClassType superClassType
: superClassTypes
) {
262 PsiClass resolvedSuperClass
= superClassType
.resolve();
264 if (resolvedSuperClass
== null) continue;
265 PsiMethod
[] superClassMethods
= resolvedSuperClass
.getMethods();
266 final HashSet
<MethodSignature
> supers
= new HashSet
<MethodSignature
>(3);
268 for (PsiMethod superClassMethod
: superClassMethods
) {
269 MethodSignature superMethodSignature
= createMethodSignature(superClassMethod
);
271 if (PsiImplUtil
.isExtendsSignature(superMethodSignature
, signature
) && !dominated(superMethodSignature
, discoveredSupers
)) {
272 if (allowStatic
|| !superClassMethod
.getModifierList().hasExplicitModifier(PsiModifier
.STATIC
)) {
273 methods
.add(superClassMethod
);
274 supers
.add(superMethodSignature
);
275 discoveredSupers
.add(superMethodSignature
);
280 findSuperMethodRecursively(methods
, resolvedSuperClass
, allowStatic
, visited
, signature
, discoveredSupers
);
281 discoveredSupers
.removeAll(supers
);
285 private static boolean dominated(MethodSignature signature
, Iterable
<MethodSignature
> supersInInheritor
) {
286 for (MethodSignature sig1
: supersInInheritor
) {
287 if (PsiImplUtil
.isExtendsSignature(signature
, sig1
)) return true;
293 public PsiMethod
[] findDeepestSuperMethods() {
294 List
<PsiMethod
> methods
= new ArrayList
<PsiMethod
>();
295 findDeepestSuperMethodsForClass(methods
, this);
296 return methods
.toArray(new PsiMethod
[methods
.size()]);
299 private void findDeepestSuperMethodsForClass(List
<PsiMethod
> collectedMethods
, PsiMethod method
) {
300 PsiClassType
[] superClassTypes
= method
.getContainingClass().getSuperTypes();
302 for (PsiClassType superClassType
: superClassTypes
) {
303 PsiClass resolvedSuperClass
= superClassType
.resolve();
305 if (resolvedSuperClass
== null) continue;
306 PsiMethod
[] superClassMethods
= resolvedSuperClass
.getMethods();
308 for (PsiMethod superClassMethod
: superClassMethods
) {
309 MethodSignature superMethodSignature
= superClassMethod
.getHierarchicalMethodSignature();
310 final HierarchicalMethodSignature thisMethodSignature
= getHierarchicalMethodSignature();
312 if (superMethodSignature
.equals(thisMethodSignature
) &&
313 !superClassMethod
.getModifierList().hasExplicitModifier(PsiModifier
.STATIC
)) {
314 checkForMethodOverriding(collectedMethods
, superClassMethod
);
316 findDeepestSuperMethodsForClass(collectedMethods
, superClassMethod
);
321 private static void checkForMethodOverriding(List
<PsiMethod
> collectedMethods
, PsiMethod superClassMethod
) {
323 while (i
< collectedMethods
.size()) {
324 PsiMethod collectedMethod
= collectedMethods
.get(i
);
325 if (collectedMethod
.getContainingClass().equals(superClassMethod
.getContainingClass()) ||
326 collectedMethod
.getContainingClass().isInheritor(superClassMethod
.getContainingClass(), true)) {
327 collectedMethods
.remove(collectedMethod
);
332 collectedMethods
.add(superClassMethod
);
336 public PsiMethod
[] findSuperMethods(boolean checkAccess
) {
337 return PsiSuperMethodImplUtil
.findSuperMethods(this, checkAccess
);
339 /*PsiClass containingClass = getContainingClass();
341 Set<PsiMethod> methods = new HashSet<PsiMethod>();
342 findSuperMethodRecursively(methods, containingClass, false, new HashSet<PsiClass>(), createMethodSignature(this),
343 new HashSet<MethodSignature>());
345 return methods.toArray(new PsiMethod[methods.size()]);*/
349 public PsiMethod
[] findSuperMethods(PsiClass parentClass
) {
350 return PsiSuperMethodImplUtil
.findSuperMethods(this, parentClass
);
351 /*Set<PsiMethod> methods = new HashSet<PsiMethod>();
352 findSuperMethodRecursively(methods, parentClass, false, new HashSet<PsiClass>(), createMethodSignature(this),
353 new HashSet<MethodSignature>());
354 return methods.toArray(new PsiMethod[methods.size()]);*/
358 public List
<MethodSignatureBackedByPsiMethod
> findSuperMethodSignaturesIncludingStatic(boolean checkAccess
) {
359 return PsiSuperMethodImplUtil
.findSuperMethodSignaturesIncludingStatic(this, checkAccess
);
360 /*PsiClass containingClass = getContainingClass();
362 Set<PsiMethod> methods = new HashSet<PsiMethod>();
363 final MethodSignature signature = createMethodSignature(this);
364 findSuperMethodRecursively(methods, containingClass, true, new HashSet<PsiClass>(), signature, new HashSet<MethodSignature>());
366 List<MethodSignatureBackedByPsiMethod> result = new ArrayList<MethodSignatureBackedByPsiMethod>();
367 for (PsiMethod method : methods) {
368 result.add(method.getHierarchicalMethodSignature());
374 public static MethodSignature
createMethodSignature(PsiMethod method
) {
375 final PsiParameter
[] parameters
= method
.getParameterList().getParameters();
376 PsiType
[] types
= new PsiType
[parameters
.length
];
377 for (int i
= 0; i
< types
.length
; i
++) {
378 types
[i
] = parameters
[i
].getType();
380 return MethodSignatureUtil
.createMethodSignature(method
.getName(), types
, PsiTypeParameter
.EMPTY_ARRAY
, PsiSubstitutor
.EMPTY
);
384 public PsiMethod
[] findSuperMethods() {
385 return PsiSuperMethodImplUtil
.findSuperMethods(this);
386 /*PsiClass containingClass = getContainingClass();
387 if (containingClass == null) return PsiMethod.EMPTY_ARRAY;
389 Set<PsiMethod> methods = new HashSet<PsiMethod>();
390 findSuperMethodRecursively(methods, containingClass, false, new HashSet<PsiClass>(), createMethodSignature(this),
391 new HashSet<MethodSignature>());
393 return methods.toArray(new PsiMethod[methods.size()]);*/
397 * @deprecated use {@link #findDeepestSuperMethods()} instead
401 public PsiMethod
findDeepestSuperMethod() {
406 public GrModifierList
getModifierList() {
407 GrModifierListImpl list
= findChildByClass(GrModifierListImpl
.class);
412 public boolean hasModifierProperty(@NonNls @NotNull String name
) {
413 if (name
.equals(PsiModifier
.ABSTRACT
)) {
414 final PsiClass containingClass
= getContainingClass();
415 if (containingClass
!= null && containingClass
.isInterface()) return true;
418 return getModifierList().hasModifierProperty(name
);
422 public String
getName() {
423 return PsiImplUtil
.getName(this);
427 public HierarchicalMethodSignature
getHierarchicalMethodSignature() {
428 return PsiSuperMethodImplUtil
.getHierarchicalMethodSignature(this);
431 public PsiElement
setName(@NonNls @NotNull String name
) throws IncorrectOperationException
{
432 PsiImplUtil
.setName(name
, getNameIdentifierGroovy());
436 public boolean hasTypeParameters() {
437 return getTypeParameters().length
> 0;
441 public GrTypeParameterList
getTypeParameterList() {
442 return findChildByClass(GrTypeParameterList
.class);
446 public GrTypeParameter
[] getTypeParameters() {
447 final GrTypeParameterList list
= getTypeParameterList();
449 return list
.getTypeParameters();
452 return GrTypeParameter
.EMPTY_ARRAY
;
455 public PsiClass
getContainingClass() {
456 PsiElement parent
= getParent();
457 if (parent
instanceof GrTypeDefinitionBody
) {
458 final PsiElement pparent
= parent
.getParent();
459 if (pparent
instanceof PsiClass
) {
460 return (PsiClass
)pparent
;
465 final PsiFile file
= getContainingFile();
466 if (file
instanceof GroovyFileBase
) {
467 return ((GroovyFileBase
)file
).getScriptClass();
474 public GrDocComment
getDocComment() {
475 return GrDocCommentUtil
.findDocComment(this);
478 public boolean isDeprecated() {
483 public SearchScope
getUseScope() {
484 return com
.intellij
.psi
.impl
.PsiImplUtil
.getMemberUseScope(this);
487 public PsiElement
getOriginalElement() {
488 final PsiClass containingClass
= getContainingClass();
489 if (containingClass
== null) return this;
490 PsiClass originalClass
= (PsiClass
)containingClass
.getOriginalElement();
491 final PsiMethod originalMethod
= originalClass
.findMethodBySignature(this, false);
492 return originalMethod
!= null ? originalMethod
: this;
497 public void delete() throws IncorrectOperationException
{
498 PsiElement parent
= getParent();
499 if (parent
instanceof GroovyFileImpl
|| parent
instanceof GrTypeDefinitionBody
) {
503 throw new IncorrectOperationException("Invalid enclosing type definition");
507 public Set
<String
>[] getNamedParametersArray() {
508 GrOpenBlock body
= getBlock();
509 if (body
== null) return new HashSet
[0];
511 List
<Set
<String
>> namedParameters
= new LinkedList
<Set
<String
>>();
512 GrParameter
[] parameters
= getParameters();
513 for (int i
= 0, parametersLength
= parameters
.length
; i
< parametersLength
; i
++) {
514 GrParameter parameter
= parameters
[i
];
515 PsiType type
= parameter
.getTypeGroovy();
516 GrTypeElement typeElement
= parameter
.getTypeElementGroovy();
517 //equalsToText can't be called here because of stub creating
519 if (type
== null || type
.getPresentableText() == null || type
.getPresentableText().endsWith("Map") || typeElement
== null) {
520 PsiElement expression
= parameter
.getNameIdentifierGroovy();
522 final String paramName
= expression
.getText();
523 final HashSet
<String
> set
= new HashSet
<String
>();
524 namedParameters
.add(set
);
526 body
.accept(new GrNamedArgumentSearchVisitor(paramName
, set
));
529 return namedParameters
.toArray(new HashSet
[0]);
532 public PsiMethodReceiver
getMethodReceiver() {
535 public PsiType
getReturnTypeNoResolve() {
536 return getReturnType();
540 public boolean isEquivalentTo(PsiElement another
) {
541 return PsiClassImplUtil
.isMethodEquivalentTo(this, another
);