groovy method's return type shouldn't be null (IDEA-50536)
[fedora-idea.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / lang / psi / impl / statements / typedef / members / GrMethodBaseImpl.java
blob15384571999deeaa61d9bb0111769bdf4207c083
1 /*
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;
69 import javax.swing.*;
70 import java.util.*;
72 /**
73 * @author ilyas
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) {
82 super(node);
85 public void accept(GroovyElementVisitor visitor) {
86 visitor.visitMethod(this);
89 public int getTextOffset() {
90 return getNameIdentifierGroovy().getTextRange().getStartOffset();
93 @NotNull
94 public PsiElement getNameIdentifierGroovy() {
95 return findChildByType(TokenSets.PROPERTY_NAMES);
98 @Nullable
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);
108 return;
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);
126 @Nullable
127 public PsiType getDeclaredReturnType() {
128 final GrTypeElement typeElement = getReturnTypeElementGroovy();
129 if (typeElement != null) return typeElement.getType();
130 return null;
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);
147 return true;
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());
163 return inferred;
165 if (inferred != null && inferred != PsiType.NULL) {
166 if (nominal.isAssignableFrom(inferred)) return inferred;
168 return nominal;
171 @Nullable
172 private PsiType getNominalType(GrMethod method) {
173 GrTypeElement element = method.getReturnTypeElementGroovy();
174 return element != null ? element.getType() : null;
177 @Nullable
178 private PsiType getInferredType(GrMethod method) {
179 final GrOpenBlock block = method.getBlock();
180 if (block == null) return null;
182 if (GroovyPsiManager.isTypeBeingInferred(method)) {
183 return null;
186 return GroovyPsiManager.inferType(method, new MethodTypeInferencer(block));
190 //PsiMethod implementation
191 @Nullable
192 public PsiType getReturnType() {
193 return GroovyPsiManager.getInstance(getProject()).getType(this, ourTypesCalculator);
196 @Override
197 public Icon getIcon(int flags) {
198 RowIcon baseIcon = createLayeredIcon(GroovyIcons.METHOD, ElementPresentationUtil.getFlags(this, false));
199 return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon);
202 @Override
203 public ItemPresentation getPresentation() {
204 return JavaPresentationUtil.getMethodPresentation(this);
207 @Nullable
208 public PsiTypeElement getReturnTypeElement() {
209 return null;
212 @NotNull
213 public GrParameterList getParameterList() {
214 GrParameterList parameterList = (GrParameterList)findChildByType(GroovyElementTypes.PARAMETERS_LIST);
215 assert parameterList != null;
216 return parameterList;
219 @NotNull
220 public PsiReferenceList getThrowsList() {
221 GrThrowsClause clause = findChildByClass(GrThrowsClause.class);
222 assert clause != null;
223 return clause;
226 @Nullable
227 public PsiCodeBlock getBody() {
228 return null;
231 public boolean isConstructor() {
232 return false;
235 public boolean isVarArgs() {
236 GrParameter[] parameters = getParameters();
237 return parameters.length > 0 && parameters[parameters.length - 1].isVarArgs();
240 @NotNull
241 public MethodSignature getSignature(@NotNull PsiSubstitutor substitutor) {
242 return MethodSignatureBackedByPsiMethod.create(this, substitutor);
245 @Nullable
246 public PsiIdentifier getNameIdentifier() {
247 return PsiUtil.getJavaNameIdentifier(this);
250 private static void findSuperMethodRecursively(Set<PsiMethod> methods,
251 PsiClass psiClass,
252 boolean allowStatic,
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;
289 return false;
292 @NotNull
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) {
322 int i = 0;
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);
328 continue;
330 i++;
332 collectedMethods.add(superClassMethod);
335 @NotNull
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()]);*/
348 @NotNull
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()]);*/
357 @NotNull
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());
371 return result;*/
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);
383 @NotNull
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
400 @Nullable
401 public PsiMethod findDeepestSuperMethod() {
402 return null;
405 @NotNull
406 public GrModifierList getModifierList() {
407 GrModifierListImpl list = findChildByClass(GrModifierListImpl.class);
408 assert list != null;
409 return list;
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);
421 @NotNull
422 public String getName() {
423 return PsiImplUtil.getName(this);
426 @NotNull
427 public HierarchicalMethodSignature getHierarchicalMethodSignature() {
428 return PsiSuperMethodImplUtil.getHierarchicalMethodSignature(this);
431 public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
432 PsiImplUtil.setName(name, getNameIdentifierGroovy());
433 return this;
436 public boolean hasTypeParameters() {
437 return getTypeParameters().length > 0;
440 @Nullable
441 public GrTypeParameterList getTypeParameterList() {
442 return findChildByClass(GrTypeParameterList.class);
445 @NotNull
446 public GrTypeParameter[] getTypeParameters() {
447 final GrTypeParameterList list = getTypeParameterList();
448 if (list != null) {
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();
470 return null;
473 @Nullable
474 public GrDocComment getDocComment() {
475 return GrDocCommentUtil.findDocComment(this);
478 public boolean isDeprecated() {
479 return false;
482 @NotNull
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) {
500 super.delete();
501 return;
503 throw new IncorrectOperationException("Invalid enclosing type definition");
506 @NotNull
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() {
533 return null;
535 public PsiType getReturnTypeNoResolve() {
536 return getReturnType();
539 @Override
540 public boolean isEquivalentTo(PsiElement another) {
541 return PsiClassImplUtil.isMethodEquivalentTo(this, another);