d1e9ff6ed01d68e5185d5d4d190c9af1a73aebea
[idea/community.git] / java / java-psi-impl / src / com / intellij / psi / impl / compiled / ClsMethodImpl.java
1 /*
2  * Copyright 2000-2013 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 package com.intellij.psi.impl.compiled;
17
18 import com.intellij.navigation.ItemPresentation;
19 import com.intellij.navigation.ItemPresentationProviders;
20 import com.intellij.openapi.extensions.Extensions;
21 import com.intellij.openapi.util.AtomicNotNullLazyValue;
22 import com.intellij.openapi.util.NotNullLazyValue;
23 import com.intellij.openapi.util.text.StringUtil;
24 import com.intellij.psi.*;
25 import com.intellij.psi.impl.ElementPresentationUtil;
26 import com.intellij.psi.impl.PsiClassImplUtil;
27 import com.intellij.psi.impl.PsiImplUtil;
28 import com.intellij.psi.impl.PsiSuperMethodImplUtil;
29 import com.intellij.psi.impl.cache.TypeInfo;
30 import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
31 import com.intellij.psi.impl.java.stubs.PsiMethodStub;
32 import com.intellij.psi.impl.source.SourceTreeToPsiMap;
33 import com.intellij.psi.impl.source.tree.TreeElement;
34 import com.intellij.psi.scope.PsiScopeProcessor;
35 import com.intellij.psi.scope.util.PsiScopesUtil;
36 import com.intellij.psi.search.SearchScope;
37 import com.intellij.psi.util.MethodSignature;
38 import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
39 import com.intellij.psi.util.MethodSignatureUtil;
40 import com.intellij.ui.RowIcon;
41 import com.intellij.util.PlatformIcons;
42 import org.jetbrains.annotations.NotNull;
43 import org.jetbrains.annotations.Nullable;
44
45 import javax.swing.*;
46 import java.util.List;
47
48 public class ClsMethodImpl extends ClsMemberImpl<PsiMethodStub> implements PsiAnnotationMethod {
49   private final NotNullLazyValue<PsiTypeElement> myReturnType;
50   private final NotNullLazyValue<PsiAnnotationMemberValue> myDefaultValue;
51
52   public ClsMethodImpl(final PsiMethodStub stub) {
53     super(stub);
54
55     myReturnType = isConstructor() ? null : new AtomicNotNullLazyValue<PsiTypeElement>() {
56       @NotNull
57       @Override
58       protected PsiTypeElement compute() {
59         PsiMethodStub stub = getStub();
60         String typeText = TypeInfo.createTypeText(stub.getReturnTypeText(false));
61         assert typeText != null : stub;
62         return new ClsTypeElementImpl(ClsMethodImpl.this, typeText, ClsTypeElementImpl.VARIANCE_NONE);
63       }
64     };
65
66     final String text = getStub().getDefaultValueText();
67     myDefaultValue = StringUtil.isEmptyOrSpaces(text) ? null : new AtomicNotNullLazyValue<PsiAnnotationMemberValue>() {
68       @NotNull
69       @Override
70       protected PsiAnnotationMemberValue compute() {
71         return ClsParsingUtil.createMemberValueFromText(text, getManager(), ClsMethodImpl.this);
72       }
73     };
74   }
75
76   @Override
77   @NotNull
78   public PsiElement[] getChildren() {
79     return getChildren(getDocComment(), getModifierList(), getReturnTypeElement(), getNameIdentifier(), getParameterList(),
80                        getThrowsList(), getDefaultValue());
81   }
82
83   @Override
84   public PsiClass getContainingClass() {
85     return (PsiClass)getParent();
86   }
87
88   @Override
89   @NotNull
90   public PsiMethod[] findSuperMethods() {
91     return PsiSuperMethodImplUtil.findSuperMethods(this);
92   }
93
94   @Override
95   @NotNull
96   public PsiMethod[] findSuperMethods(boolean checkAccess) {
97     return PsiSuperMethodImplUtil.findSuperMethods(this, checkAccess);
98   }
99
100   @Override
101   @NotNull
102   public PsiMethod[] findSuperMethods(PsiClass parentClass) {
103     return PsiSuperMethodImplUtil.findSuperMethods(this, parentClass);
104   }
105
106   @Override
107   @NotNull
108   public List<MethodSignatureBackedByPsiMethod> findSuperMethodSignaturesIncludingStatic(boolean checkAccess) {
109     return PsiSuperMethodImplUtil.findSuperMethodSignaturesIncludingStatic(this, checkAccess);
110   }
111
112   @Override
113   public PsiMethod findDeepestSuperMethod() {
114     return PsiSuperMethodImplUtil.findDeepestSuperMethod(this);
115   }
116
117   @Override
118   @NotNull
119   public PsiMethod[] findDeepestSuperMethods() {
120     return PsiSuperMethodImplUtil.findDeepestSuperMethods(this);
121   }
122
123   @Override
124   @NotNull
125   public HierarchicalMethodSignature getHierarchicalMethodSignature() {
126     return PsiSuperMethodImplUtil.getHierarchicalMethodSignature(this);
127   }
128
129   @Override
130   public PsiTypeElement getReturnTypeElement() {
131     return myReturnType != null ? myReturnType.getValue() : null;
132   }
133
134   @Override
135   public PsiType getReturnType() {
136     PsiTypeElement typeElement = getReturnTypeElement();
137     return typeElement == null ? null : typeElement.getType();
138   }
139
140   @Override
141   @NotNull
142   public PsiModifierList getModifierList() {
143     return getStub().findChildStubByType(JavaStubElementTypes.MODIFIER_LIST).getPsi();
144   }
145
146   @Override
147   public boolean hasModifierProperty(@NotNull String name) {
148     return getModifierList().hasModifierProperty(name);
149   }
150
151   @Override
152   @NotNull
153   public PsiParameterList getParameterList() {
154     return getStub().findChildStubByType(JavaStubElementTypes.PARAMETER_LIST).getPsi();
155   }
156
157   @Override
158   @NotNull
159   public PsiReferenceList getThrowsList() {
160     return getStub().findChildStubByType(JavaStubElementTypes.THROWS_LIST).getPsi();
161   }
162
163   @Override
164   public PsiTypeParameterList getTypeParameterList() {
165     return getStub().findChildStubByType(JavaStubElementTypes.TYPE_PARAMETER_LIST).getPsi();
166   }
167
168   @Override
169   public PsiCodeBlock getBody() {
170     return null;
171   }
172
173   @Override
174   public boolean isDeprecated() {
175     return getStub().isDeprecated();
176   }
177
178   @Override
179   public PsiAnnotationMemberValue getDefaultValue() {
180     return myDefaultValue != null ? myDefaultValue.getValue() : null;
181   }
182
183   @Override
184   public boolean isConstructor() {
185     return getStub().isConstructor();
186   }
187
188   @Override
189   public boolean isVarArgs() {
190     return getStub().isVarArgs();
191   }
192
193   @Override
194   @NotNull
195   public MethodSignature getSignature(@NotNull PsiSubstitutor substitutor) {
196     return MethodSignatureBackedByPsiMethod.create(this, substitutor);
197   }
198
199   @Override
200   public void appendMirrorText(int indentLevel, @NotNull StringBuilder buffer) {
201     appendText(getDocComment(), indentLevel, buffer, NEXT_LINE);
202     appendText(getModifierList(), indentLevel, buffer, "");
203     appendText(getTypeParameterList(), indentLevel, buffer, " ");
204     if (!isConstructor()) {
205       appendText(getReturnTypeElement(), indentLevel, buffer, " ");
206     }
207     appendText(getNameIdentifier(), indentLevel, buffer, "");
208     appendText(getParameterList(), indentLevel, buffer);
209
210     PsiReferenceList throwsList = getThrowsList();
211     if (throwsList.getReferencedTypes().length > 0) {
212       buffer.append(' ');
213       appendText(throwsList, indentLevel, buffer);
214     }
215
216     PsiAnnotationMemberValue defaultValue = getDefaultValue();
217     if (defaultValue != null) {
218       buffer.append(" default ");
219       appendText(defaultValue, indentLevel, buffer);
220     }
221
222     if (hasModifierProperty(PsiModifier.ABSTRACT) || hasModifierProperty(PsiModifier.NATIVE)) {
223       buffer.append(";");
224     }
225     else {
226       buffer.append(" { /* compiled code */ }");
227     }
228   }
229
230   @Override
231   public void setMirror(@NotNull TreeElement element) throws InvalidMirrorException {
232     setMirrorCheckingType(element, null);
233
234     PsiMethod mirror = SourceTreeToPsiMap.treeToPsiNotNull(element);
235
236     setMirrorIfPresent(getDocComment(), mirror.getDocComment());
237     setMirror(getModifierList(), mirror.getModifierList());
238     setMirror(getTypeParameterList(), mirror.getTypeParameterList());
239     if (!isConstructor()) {
240       setMirror(getReturnTypeElement(), mirror.getReturnTypeElement());
241     }
242     setMirror(getNameIdentifier(), mirror.getNameIdentifier());
243     setMirror(getParameterList(), mirror.getParameterList());
244     setMirror(getThrowsList(), mirror.getThrowsList());
245
246     PsiAnnotationMemberValue defaultValue = getDefaultValue();
247     if (defaultValue != null) {
248       assert mirror instanceof PsiAnnotationMethod : this;
249       setMirror(defaultValue, ((PsiAnnotationMethod)mirror).getDefaultValue());
250     }
251   }
252
253   @Override
254   public void accept(@NotNull PsiElementVisitor visitor) {
255     if (visitor instanceof JavaElementVisitor) {
256       ((JavaElementVisitor)visitor).visitMethod(this);
257     }
258     else {
259       visitor.visitElement(this);
260     }
261   }
262
263   @Override
264   public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
265                                      @NotNull ResolveState state,
266                                      PsiElement lastParent,
267                                      @NotNull PsiElement place) {
268     processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, this);
269     if (lastParent == null) return true;
270
271     if (!PsiScopesUtil.walkChildrenScopes(this, processor, state, lastParent, place)) return false;
272
273     final PsiParameter[] parameters = getParameterList().getParameters();
274     for (PsiParameter parameter : parameters) {
275       if (!processor.execute(parameter, state)) return false;
276     }
277
278     return true;
279   }
280
281   @Nullable
282   public PsiMethod getSourceMirrorMethod() {
283     PsiClass sourceClassMirror = ((ClsClassImpl)getParent()).getSourceMirrorClass();
284     if (sourceClassMirror == null) return null;
285     for (PsiMethod sourceMethod : sourceClassMirror.findMethodsByName(getName(), false)) {
286       if (MethodSignatureUtil.areParametersErasureEqual(this, sourceMethod)) {
287         return sourceMethod;
288       }
289     }
290     return null;
291   }
292
293   @Override
294   @NotNull
295   public PsiElement getNavigationElement() {
296     for (ClsCustomNavigationPolicy customNavigationPolicy : Extensions.getExtensions(ClsCustomNavigationPolicy.EP_NAME)) {
297       PsiElement navigationElement = customNavigationPolicy.getNavigationElement(this);
298       if (navigationElement != null) {
299         return navigationElement;
300       }
301     }
302
303     final PsiMethod method = getSourceMirrorMethod();
304     return method != null ? method.getNavigationElement() : this;
305   }
306
307   @Override
308   public boolean hasTypeParameters() {
309     return PsiImplUtil.hasTypeParameters(this);
310   }
311
312   @Override
313   @NotNull public PsiTypeParameter[] getTypeParameters() {
314     return PsiImplUtil.getTypeParameters(this);
315   }
316
317   @Override
318   public ItemPresentation getPresentation() {
319     return ItemPresentationProviders.getItemPresentation(this);
320   }
321
322   @Override
323   public Icon getElementIcon(final int flags) {
324     Icon methodIcon = hasModifierProperty(PsiModifier.ABSTRACT) ? PlatformIcons.ABSTRACT_METHOD_ICON : PlatformIcons.METHOD_ICON;
325     RowIcon baseIcon = ElementPresentationUtil.createLayeredIcon(methodIcon, this, false);
326     return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon);
327   }
328
329   @Override
330   public boolean isEquivalentTo(final PsiElement another) {
331     return PsiClassImplUtil.isMethodEquivalentTo(this, another);
332   }
333
334   @Override
335   @NotNull
336   public SearchScope getUseScope() {
337     return PsiImplUtil.getMemberUseScope(this);
338   }
339
340   @Override
341   protected boolean isVisibilitySupported() {
342     return true;
343   }
344
345   @Override
346   public String toString() {
347     return "PsiMethod:" + getName();
348   }
349 }