EditorConfig documentation test
[idea/community.git] / java / java-psi-impl / src / com / intellij / psi / impl / compiled / ClsClassImpl.java
1 // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.psi.impl.compiled;
3
4 import com.intellij.navigation.ItemPresentation;
5 import com.intellij.navigation.ItemPresentationProviders;
6 import com.intellij.openapi.project.IndexNotReadyException;
7 import com.intellij.openapi.ui.Queryable;
8 import com.intellij.openapi.util.Key;
9 import com.intellij.openapi.util.Pair;
10 import com.intellij.pom.java.LanguageLevel;
11 import com.intellij.psi.*;
12 import com.intellij.psi.impl.InheritanceImplUtil;
13 import com.intellij.psi.impl.PsiClassImplUtil;
14 import com.intellij.psi.impl.PsiImplUtil;
15 import com.intellij.psi.impl.PsiSuperMethodImplUtil;
16 import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
17 import com.intellij.psi.impl.java.stubs.PsiClassStub;
18 import com.intellij.psi.impl.java.stubs.impl.PsiClassStubImpl;
19 import com.intellij.psi.impl.source.*;
20 import com.intellij.psi.impl.source.tree.TreeElement;
21 import com.intellij.psi.scope.PsiScopeProcessor;
22 import com.intellij.psi.scope.processor.MethodsProcessor;
23 import com.intellij.psi.search.SearchScope;
24 import com.intellij.psi.util.PsiUtil;
25 import com.intellij.psi.util.PsiUtilCore;
26 import com.intellij.util.containers.ContainerUtil;
27 import org.jetbrains.annotations.NonNls;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.Nullable;
30
31 import javax.swing.*;
32 import java.util.*;
33
34 import static com.intellij.util.ObjectUtils.assertNotNull;
35 import static java.util.Arrays.asList;
36
37 public class ClsClassImpl extends ClsMemberImpl<PsiClassStub<?>> implements PsiExtensibleClass, Queryable {
38   public static final Key<PsiClass> DELEGATE_KEY = Key.create("DELEGATE");
39
40   private final ClassInnerStuffCache myInnersCache = new ClassInnerStuffCache(this);
41
42   public ClsClassImpl(final PsiClassStub stub) {
43     super(stub);
44   }
45
46   @Override
47   @NotNull
48   public PsiElement[] getChildren() {
49     List<PsiElement> children = new ArrayList<>();
50     ContainerUtil.addAll(children, getChildren(getDocComment(), getModifierListInternal(), getNameIdentifier(), getExtendsList(), getImplementsList()));
51     ContainerUtil.addAll(children, getOwnFields());
52     ContainerUtil.addAll(children, getOwnMethods());
53     ContainerUtil.addAll(children, getOwnInnerClasses());
54     return PsiUtilCore.toPsiElementArray(children);
55   }
56
57   @Override
58   @NotNull
59   public PsiTypeParameterList getTypeParameterList() {
60     return assertNotNull(getStub().findChildStubByType(JavaStubElementTypes.TYPE_PARAMETER_LIST)).getPsi();
61   }
62
63   @Override
64   public boolean hasTypeParameters() {
65     return PsiImplUtil.hasTypeParameters(this);
66   }
67
68   @Override
69   @Nullable
70   public String getQualifiedName() {
71     return getStub().getQualifiedName();
72   }
73
74   private boolean isLocalClass() {
75     PsiClassStub<?> stub = getStub();
76     return stub instanceof PsiClassStubImpl &&
77            ((PsiClassStubImpl)stub).isLocalClassInner();
78   }
79
80   private boolean isAnonymousClass() {
81     PsiClassStub<?> stub = getStub();
82     return stub instanceof PsiClassStubImpl &&
83            ((PsiClassStubImpl)stub).isAnonymousInner();
84   }
85
86   private boolean isAnonymousOrLocalClass() {
87     return isAnonymousClass() || isLocalClass();
88   }
89
90   @Override
91   @Nullable
92   public PsiModifierList getModifierList() {
93     if (isAnonymousClass()) return null;
94     return getModifierListInternal();
95   }
96
97   private PsiModifierList getModifierListInternal() {
98     return assertNotNull(getStub().findChildStubByType(JavaStubElementTypes.MODIFIER_LIST)).getPsi();
99   }
100
101   @Override
102   public boolean hasModifierProperty(@NotNull String name) {
103     return getModifierListInternal().hasModifierProperty(name);
104   }
105
106   @Override
107   @NotNull
108   public PsiReferenceList getExtendsList() {
109     return assertNotNull(getStub().findChildStubByType(JavaStubElementTypes.EXTENDS_LIST)).getPsi();
110   }
111
112   @Override
113   @NotNull
114   public PsiReferenceList getImplementsList() {
115     return assertNotNull(getStub().findChildStubByType(JavaStubElementTypes.IMPLEMENTS_LIST)).getPsi();
116   }
117
118   @Override
119   @NotNull
120   public PsiClassType[] getExtendsListTypes() {
121     return PsiClassImplUtil.getExtendsListTypes(this);
122   }
123
124   @Override
125   @NotNull
126   public PsiClassType[] getImplementsListTypes() {
127     return PsiClassImplUtil.getImplementsListTypes(this);
128   }
129
130   @Override
131   public PsiClass getSuperClass() {
132     return PsiClassImplUtil.getSuperClass(this);
133   }
134
135   @NotNull
136   @Override
137   public PsiClass[] getInterfaces() {
138     return PsiClassImplUtil.getInterfaces(this);
139   }
140
141   @Override
142   @NotNull
143   public PsiClass[] getSupers() {
144     if (CommonClassNames.JAVA_LANG_OBJECT.equals(getQualifiedName())) {
145       return PsiClass.EMPTY_ARRAY;
146     }
147     return PsiClassImplUtil.getSupers(this);
148   }
149
150   @Override
151   @NotNull
152   public PsiClassType[] getSuperTypes() {
153     if (CommonClassNames.JAVA_LANG_OBJECT.equals(getQualifiedName())) {
154       return PsiClassType.EMPTY_ARRAY;
155     }
156     return PsiClassImplUtil.getSuperTypes(this);
157   }
158
159   @Override
160   public PsiClass getContainingClass() {
161     PsiElement parent = getParent();
162     return parent instanceof PsiClass ? (PsiClass)parent : null;
163   }
164
165   @Override
166   @NotNull
167   public Collection<HierarchicalMethodSignature> getVisibleSignatures() {
168     return PsiSuperMethodImplUtil.getVisibleSignatures(this);
169   }
170
171   @Override
172   @NotNull
173   public PsiField[] getFields() {
174     return myInnersCache.getFields();
175   }
176
177   @Override
178   @NotNull
179   public PsiMethod[] getMethods() {
180     return myInnersCache.getMethods();
181   }
182
183   @Override
184   @NotNull
185   public PsiMethod[] getConstructors() {
186     return myInnersCache.getConstructors();
187   }
188
189   @Override
190   @NotNull
191   public PsiClass[] getInnerClasses() {
192     return myInnersCache.getInnerClasses();
193   }
194
195   @NotNull
196   @Override
197   public List<PsiField> getOwnFields() {
198     return asList(getStub().getChildrenByType(Constants.FIELD_BIT_SET, PsiField.ARRAY_FACTORY));
199   }
200
201   @NotNull
202   @Override
203   public List<PsiMethod> getOwnMethods() {
204     return asList(getStub().getChildrenByType(Constants.METHOD_BIT_SET, PsiMethod.ARRAY_FACTORY));
205   }
206
207   @NotNull
208   @Override
209   public List<PsiClass> getOwnInnerClasses() {
210     PsiClass[] classes = getStub().getChildrenByType(JavaStubElementTypes.CLASS, PsiClass.ARRAY_FACTORY);
211     if (classes.length == 0) return Collections.emptyList();
212
213     int anonymousOrLocalClassesCount = 0;
214     for(PsiClass aClass:classes) {
215       if (aClass instanceof ClsClassImpl && ((ClsClassImpl)aClass).isAnonymousOrLocalClass()) {
216         ++anonymousOrLocalClassesCount;
217       }
218     }
219     if (anonymousOrLocalClassesCount == 0) return asList(classes);
220
221     ArrayList<PsiClass> result = new ArrayList<>(classes.length - anonymousOrLocalClassesCount);
222     for(PsiClass aClass:classes) {
223       if (!(aClass instanceof ClsClassImpl) || !((ClsClassImpl)aClass).isAnonymousOrLocalClass()) {
224         result.add(aClass);
225       }
226     }
227     return result;
228   }
229
230   @Override
231   @NotNull
232   public PsiClassInitializer[] getInitializers() {
233     return PsiClassInitializer.EMPTY_ARRAY;
234   }
235
236   @Override
237   @NotNull
238   public PsiTypeParameter[] getTypeParameters() {
239     return PsiImplUtil.getTypeParameters(this);
240   }
241
242   @Override
243   @NotNull
244   public PsiField[] getAllFields() {
245     return PsiClassImplUtil.getAllFields(this);
246   }
247
248   @Override
249   @NotNull
250   public PsiMethod[] getAllMethods() {
251     return PsiClassImplUtil.getAllMethods(this);
252   }
253
254   @Override
255   @NotNull
256   public PsiClass[] getAllInnerClasses() {
257     return PsiClassImplUtil.getAllInnerClasses(this);
258   }
259
260   @Override
261   public PsiField findFieldByName(String name, boolean checkBases) {
262     return myInnersCache.findFieldByName(name, checkBases);
263   }
264
265   @Override
266   public PsiMethod findMethodBySignature(PsiMethod patternMethod, boolean checkBases) {
267     return PsiClassImplUtil.findMethodBySignature(this, patternMethod, checkBases);
268   }
269
270   @Override
271   @NotNull
272   public PsiMethod[] findMethodsBySignature(PsiMethod patternMethod, boolean checkBases) {
273     return PsiClassImplUtil.findMethodsBySignature(this, patternMethod, checkBases);
274   }
275
276   @Override
277   @NotNull
278   public PsiMethod[] findMethodsByName(String name, boolean checkBases) {
279     return myInnersCache.findMethodsByName(name, checkBases);
280   }
281
282   @Override
283   @NotNull
284   public List<Pair<PsiMethod, PsiSubstitutor>> findMethodsAndTheirSubstitutorsByName(String name, boolean checkBases) {
285     return PsiClassImplUtil.findMethodsAndTheirSubstitutorsByName(this, name, checkBases);
286   }
287
288   @Override
289   @NotNull
290   public List<Pair<PsiMethod, PsiSubstitutor>> getAllMethodsAndTheirSubstitutors() {
291     return PsiClassImplUtil.getAllWithSubstitutorsByMap(this, PsiClassImplUtil.MemberType.METHOD);
292   }
293
294   @Override
295   public PsiClass findInnerClassByName(String name, boolean checkBases) {
296     return myInnersCache.findInnerClassByName(name, checkBases);
297   }
298
299   @Override
300   public boolean isDeprecated() {
301     return getStub().isDeprecated() || PsiImplUtil.isDeprecatedByAnnotation(this);
302   }
303
304   public String getSourceFileName() {
305     final String sfn = getStub().getSourceFileName();
306     return sfn != null ? sfn : obtainSourceFileNameFromClassFileName();
307   }
308
309   @NonNls
310   private String obtainSourceFileNameFromClassFileName() {
311     final String name = getContainingFile().getName();
312     int i = name.indexOf('$');
313     if (i < 0) {
314       i = name.indexOf('.');
315       if (i < 0) {
316         i = name.length();
317       }
318     }
319     return name.substring(0, i) + ".java";
320   }
321
322   @Override
323   public PsiJavaToken getLBrace() {
324     return null;
325   }
326
327   @Override
328   public PsiJavaToken getRBrace() {
329     return null;
330   }
331
332   @Override
333   public boolean isInterface() {
334     return getStub().isInterface();
335   }
336
337   @Override
338   public boolean isAnnotationType() {
339     return getStub().isAnnotationType();
340   }
341
342   @Override
343   public boolean isEnum() {
344     return getStub().isEnum();
345   }
346
347   @Override
348   public void appendMirrorText(final int indentLevel, @NotNull @NonNls final StringBuilder buffer) {
349     appendText(getDocComment(), indentLevel, buffer, NEXT_LINE);
350
351     appendText(getModifierListInternal(), indentLevel, buffer);
352     buffer.append(isEnum() ? "enum " : isAnnotationType() ? "@interface " : isInterface() ? "interface " : "class ");
353     appendText(getNameIdentifier(), indentLevel, buffer, " ");
354     appendText(getTypeParameterList(), indentLevel, buffer, " ");
355     appendText(getExtendsList(), indentLevel, buffer, " ");
356     appendText(getImplementsList(), indentLevel, buffer, " ");
357
358     buffer.append('{');
359
360     int newIndentLevel = indentLevel + getIndentSize();
361     List<PsiField> fields = getOwnFields();
362     List<PsiMethod> methods = getOwnMethods();
363     List<PsiClass> classes = getOwnInnerClasses();
364
365     if (!fields.isEmpty()) {
366       goNextLine(newIndentLevel, buffer);
367
368       for (int i = 0; i < fields.size(); i++) {
369         PsiField field = fields.get(i);
370         appendText(field, newIndentLevel, buffer);
371
372         if (field instanceof ClsEnumConstantImpl) {
373           if (i < fields.size() - 1 && fields.get(i + 1) instanceof ClsEnumConstantImpl) {
374             buffer.append(", ");
375           }
376           else {
377             buffer.append(';');
378             if (i < fields.size() - 1) {
379               buffer.append('\n');
380               goNextLine(newIndentLevel, buffer);
381             }
382           }
383         }
384         else if (i < fields.size() - 1) {
385           goNextLine(newIndentLevel, buffer);
386         }
387       }
388     }
389     else if (isEnum() && methods.size() + classes.size() > 0) {
390       goNextLine(newIndentLevel, buffer);
391       buffer.append(";");
392     }
393
394     if (!methods.isEmpty()) {
395       if (isEnum() || !fields.isEmpty()) {
396         buffer.append('\n');
397       }
398       goNextLine(newIndentLevel, buffer);
399
400       for (int i = 0; i < methods.size(); i++) {
401         appendText(methods.get(i), newIndentLevel, buffer);
402
403         if (i < methods.size() - 1) {
404           buffer.append('\n');
405           goNextLine(newIndentLevel, buffer);
406         }
407       }
408     }
409
410     if (!classes.isEmpty()) {
411       if (fields.size() + methods.size() > 0) {
412         buffer.append('\n');
413       }
414       goNextLine(newIndentLevel, buffer);
415
416       for (int i = 0; i < classes.size(); i++) {
417         appendText(classes.get(i), newIndentLevel, buffer);
418
419         if (i < classes.size() - 1) {
420           buffer.append('\n');
421           goNextLine(newIndentLevel, buffer);
422         }
423       }
424     }
425
426     goNextLine(indentLevel, buffer);
427     buffer.append('}');
428   }
429
430   @Override
431   public void setMirror(@NotNull TreeElement element) throws InvalidMirrorException {
432     setMirrorCheckingType(element, null);
433
434     PsiClass mirror = SourceTreeToPsiMap.treeToPsiNotNull(element);
435
436     setMirrorIfPresent(getDocComment(), mirror.getDocComment());
437
438     PsiModifierList modifierList = getModifierList();
439     if (modifierList != null) setMirror(modifierList, mirror.getModifierList());
440     setMirror(getNameIdentifier(), mirror.getNameIdentifier());
441     setMirror(getTypeParameterList(), mirror.getTypeParameterList());
442     setMirror(getExtendsList(), mirror.getExtendsList());
443     setMirror(getImplementsList(), mirror.getImplementsList());
444
445     if (mirror instanceof PsiExtensibleClass) {
446       PsiExtensibleClass extMirror = (PsiExtensibleClass)mirror;
447       setMirrors(getOwnFields(), extMirror.getOwnFields());
448       setMirrors(getOwnMethods(), extMirror.getOwnMethods());
449       setMirrors(getOwnInnerClasses(), extMirror.getOwnInnerClasses());
450     }
451     else {
452       setMirrors(getOwnFields(), asList(mirror.getFields()));
453       setMirrors(getOwnMethods(), asList(mirror.getMethods()));
454       setMirrors(getOwnInnerClasses(), asList(mirror.getInnerClasses()));
455     }
456   }
457
458   @Override
459   public void accept(@NotNull PsiElementVisitor visitor) {
460     if (visitor instanceof JavaElementVisitor) {
461       ((JavaElementVisitor)visitor).visitClass(this);
462     }
463     else {
464       visitor.visitElement(this);
465     }
466   }
467
468   @Override
469   @NonNls
470   public String toString() {
471     return "PsiClass:" + getName();
472   }
473
474   @Override
475   public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
476                                      @NotNull ResolveState state,
477                                      PsiElement lastParent,
478                                      @NotNull PsiElement place) {
479     if (isEnum()) {
480       if (!PsiClassImplUtil.processDeclarationsInEnum(processor, state, myInnersCache)) return false;
481     }
482
483     LanguageLevel level = processor instanceof MethodsProcessor ? ((MethodsProcessor)processor).getLanguageLevel() : PsiUtil.getLanguageLevel(place);
484     return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, level, false);
485   }
486
487   @Override
488   public PsiElement getScope() {
489     return getParent();
490   }
491
492   @Override
493   public boolean isInheritorDeep(PsiClass baseClass, PsiClass classToByPass) {
494     return InheritanceImplUtil.isInheritorDeep(this, baseClass, classToByPass);
495   }
496
497   @Override
498   public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
499     return InheritanceImplUtil.isInheritor(this, baseClass, checkDeep);
500   }
501
502   @Nullable
503   public PsiClass getSourceMirrorClass() {
504     final PsiClass delegate = getUserData(DELEGATE_KEY);
505     if (delegate instanceof ClsClassImpl) {
506       return ((ClsClassImpl)delegate).getSourceMirrorClass();
507     }
508
509     final String name = getName();
510     final PsiElement parent = getParent();
511     if (parent instanceof PsiFile) {
512       if (!(parent instanceof PsiClassOwner)) return null;
513
514       PsiClassOwner fileNavigationElement = (PsiClassOwner)parent.getNavigationElement();
515       if (fileNavigationElement == parent) return null;
516
517       for (PsiClass aClass : fileNavigationElement.getClasses()) {
518         if (name.equals(aClass.getName())) return aClass;
519       }
520     }
521     else if (parent != null) {
522       ClsClassImpl parentClass = (ClsClassImpl)parent;
523       PsiClass parentSourceMirror = parentClass.getSourceMirrorClass();
524       if (parentSourceMirror == null) return null;
525       PsiClass[] innerClasses = parentSourceMirror.getInnerClasses();
526       for (PsiClass innerClass : innerClasses) {
527         if (name.equals(innerClass.getName())) return innerClass;
528       }
529     }
530     else {
531       throw new PsiInvalidElementAccessException(this);
532     }
533
534     return null;
535   }
536
537   @Override
538   @NotNull
539   public PsiElement getNavigationElement() {
540     for (ClsCustomNavigationPolicy navigationPolicy : ClsCustomNavigationPolicy.EP_NAME.getExtensionList()) {
541       try {
542         PsiElement navigationElement = navigationPolicy.getNavigationElement(this);
543         if (navigationElement != null) return navigationElement;
544       }
545       catch (IndexNotReadyException ignored) { }
546     }
547
548     try {
549       PsiClass aClass = getSourceMirrorClass();
550       if (aClass != null) return aClass.getNavigationElement();
551
552       if ("package-info".equals(getName())) {
553         PsiElement parent = getParent();
554         if (parent instanceof ClsFileImpl) {
555           PsiElement sourceFile = parent.getNavigationElement();
556           if (sourceFile instanceof PsiJavaFile) {
557             return sourceFile;
558           }
559         }
560       }
561     }
562     catch (IndexNotReadyException ignore) { }
563
564     return this;
565   }
566
567   @Override
568   public ItemPresentation getPresentation() {
569     return ItemPresentationProviders.getItemPresentation(this);
570   }
571
572   @Override
573   public Icon getElementIcon(final int flags) {
574     return PsiClassImplUtil.getClassIcon(flags, this);
575   }
576
577   @Override
578   public boolean isEquivalentTo(final PsiElement another) {
579     return PsiClassImplUtil.isClassEquivalentTo(this, another);
580   }
581
582   @Override
583   @NotNull
584   public SearchScope getUseScope() {
585     return PsiClassImplUtil.getClassUseScope(this);
586   }
587
588   @Override
589   public void putInfo(@NotNull Map<String, String> info) {
590     PsiClassImpl.putInfo(this, info);
591   }
592
593   @Override
594   protected boolean isVisibilitySupported() {
595     return true;
596   }
597 }