blob: c6d9962392c627a5443087f484c9802132586ba6 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi.impl.compiled;
import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.ItemPresentationProviders;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.ui.Queryable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.InheritanceImplUtil;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.PsiSuperMethodImplUtil;
import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
import com.intellij.psi.impl.java.stubs.PsiClassStub;
import com.intellij.psi.impl.source.*;
import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.scope.processor.MethodsProcessor;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class ClsClassImpl extends ClsMemberImpl<PsiClassStub<?>> implements PsiExtensibleClass, PsiQualifiedNamedElement, Queryable {
public static final Key<PsiClass> DELEGATE_KEY = Key.create("DELEGATE");
private final ClassInnerStuffCache myInnersCache = new ClassInnerStuffCache(this);
public ClsClassImpl(final PsiClassStub stub) {
super(stub);
}
@Override
@NotNull
public PsiElement[] getChildren() {
List<PsiElement> children = ContainerUtil.newArrayList();
ContainerUtil.addAll(children, getChildren(getDocComment(), getModifierList(), getNameIdentifier(), getExtendsList(), getImplementsList()));
ContainerUtil.addAll(children, getOwnFields());
ContainerUtil.addAll(children, getOwnMethods());
ContainerUtil.addAll(children, getOwnInnerClasses());
return PsiUtilCore.toPsiElementArray(children);
}
@Override
@NotNull
public PsiTypeParameterList getTypeParameterList() {
return getStub().findChildStubByType(JavaStubElementTypes.TYPE_PARAMETER_LIST).getPsi();
}
@Override
public boolean hasTypeParameters() {
return PsiImplUtil.hasTypeParameters(this);
}
@Override
@NotNull
public String getQualifiedName() {
return getStub().getQualifiedName();
}
@Override
@NotNull
public PsiModifierList getModifierList() {
return getStub().findChildStubByType(JavaStubElementTypes.MODIFIER_LIST).getPsi();
}
@Override
public boolean hasModifierProperty(@NotNull String name) {
return getModifierList().hasModifierProperty(name);
}
@Override
@NotNull
public PsiReferenceList getExtendsList() {
return getStub().findChildStubByType(JavaStubElementTypes.EXTENDS_LIST).getPsi();
}
@Override
@NotNull
public PsiReferenceList getImplementsList() {
return getStub().findChildStubByType(JavaStubElementTypes.IMPLEMENTS_LIST).getPsi();
}
@Override
@NotNull
public PsiClassType[] getExtendsListTypes() {
return PsiClassImplUtil.getExtendsListTypes(this);
}
@Override
@NotNull
public PsiClassType[] getImplementsListTypes() {
return PsiClassImplUtil.getImplementsListTypes(this);
}
@Override
public PsiClass getSuperClass() {
return PsiClassImplUtil.getSuperClass(this);
}
@Override
public PsiClass[] getInterfaces() {
return PsiClassImplUtil.getInterfaces(this);
}
@Override
@NotNull
public PsiClass[] getSupers() {
if (CommonClassNames.JAVA_LANG_OBJECT.equals(getQualifiedName())) {
return PsiClass.EMPTY_ARRAY;
}
return PsiClassImplUtil.getSupers(this);
}
@Override
@NotNull
public PsiClassType[] getSuperTypes() {
if (CommonClassNames.JAVA_LANG_OBJECT.equals(getQualifiedName())) {
return PsiClassType.EMPTY_ARRAY;
}
return PsiClassImplUtil.getSuperTypes(this);
}
@Override
public PsiClass getContainingClass() {
PsiElement parent = getParent();
return parent instanceof PsiClass ? (PsiClass)parent : null;
}
@Override
@NotNull
public Collection<HierarchicalMethodSignature> getVisibleSignatures() {
return PsiSuperMethodImplUtil.getVisibleSignatures(this);
}
@Override
@NotNull
public PsiField[] getFields() {
return myInnersCache.getFields();
}
@Override
@NotNull
public PsiMethod[] getMethods() {
return myInnersCache.getMethods();
}
@Override
@NotNull
public PsiMethod[] getConstructors() {
return myInnersCache.getConstructors();
}
@Override
@NotNull
public PsiClass[] getInnerClasses() {
return myInnersCache.getInnerClasses();
}
@NotNull
@Override
public List<PsiField> getOwnFields() {
return Arrays.asList(getStub().getChildrenByType(Constants.FIELD_BIT_SET, PsiField.ARRAY_FACTORY));
}
@NotNull
@Override
public List<PsiMethod> getOwnMethods() {
return Arrays.asList(getStub().getChildrenByType(Constants.METHOD_BIT_SET, PsiMethod.ARRAY_FACTORY));
}
@NotNull
@Override
public List<PsiClass> getOwnInnerClasses() {
return Arrays.asList(getStub().getChildrenByType(JavaStubElementTypes.CLASS, PsiClass.ARRAY_FACTORY));
}
@Override
@NotNull
public PsiClassInitializer[] getInitializers() {
return PsiClassInitializer.EMPTY_ARRAY;
}
@Override
@NotNull
public PsiTypeParameter[] getTypeParameters() {
return PsiImplUtil.getTypeParameters(this);
}
@Override
@NotNull
public PsiField[] getAllFields() {
return PsiClassImplUtil.getAllFields(this);
}
@Override
@NotNull
public PsiMethod[] getAllMethods() {
return PsiClassImplUtil.getAllMethods(this);
}
@Override
@NotNull
public PsiClass[] getAllInnerClasses() {
return PsiClassImplUtil.getAllInnerClasses(this);
}
@Override
public PsiField findFieldByName(String name, boolean checkBases) {
return myInnersCache.findFieldByName(name, checkBases);
}
@Override
public PsiMethod findMethodBySignature(PsiMethod patternMethod, boolean checkBases) {
return PsiClassImplUtil.findMethodBySignature(this, patternMethod, checkBases);
}
@Override
@NotNull
public PsiMethod[] findMethodsBySignature(PsiMethod patternMethod, boolean checkBases) {
return PsiClassImplUtil.findMethodsBySignature(this, patternMethod, checkBases);
}
@Override
@NotNull
public PsiMethod[] findMethodsByName(String name, boolean checkBases) {
return myInnersCache.findMethodsByName(name, checkBases);
}
@Override
@NotNull
public List<Pair<PsiMethod, PsiSubstitutor>> findMethodsAndTheirSubstitutorsByName(String name, boolean checkBases) {
return PsiClassImplUtil.findMethodsAndTheirSubstitutorsByName(this, name, checkBases);
}
@Override
@NotNull
public List<Pair<PsiMethod, PsiSubstitutor>> getAllMethodsAndTheirSubstitutors() {
return PsiClassImplUtil.getAllWithSubstitutorsByMap(this, PsiClassImplUtil.MemberType.METHOD);
}
@Override
public PsiClass findInnerClassByName(String name, boolean checkBases) {
return myInnersCache.findInnerClassByName(name, checkBases);
}
@Override
public boolean isDeprecated() {
return getStub().isDeprecated();
}
public String getSourceFileName() {
final String sfn = getStub().getSourceFileName();
return sfn != null ? sfn : obtainSourceFileNameFromClassFileName();
}
@NonNls
private String obtainSourceFileNameFromClassFileName() {
final String name = getContainingFile().getName();
int i = name.indexOf('$');
if (i < 0) {
i = name.indexOf('.');
if (i < 0) {
i = name.length();
}
}
return name.substring(0, i) + ".java";
}
@Override
public PsiJavaToken getLBrace() {
return null;
}
@Override
public PsiJavaToken getRBrace() {
return null;
}
@Override
public boolean isInterface() {
return getStub().isInterface();
}
@Override
public boolean isAnnotationType() {
return getStub().isAnnotationType();
}
@Override
public boolean isEnum() {
return getStub().isEnum();
}
@Override
public void appendMirrorText(final int indentLevel, @NotNull @NonNls final StringBuilder buffer) {
appendText(getDocComment(), indentLevel, buffer, NEXT_LINE);
appendText(getModifierList(), indentLevel, buffer);
buffer.append(isEnum() ? "enum " : isAnnotationType() ? "@interface " : isInterface() ? "interface " : "class ");
appendText(getNameIdentifier(), indentLevel, buffer, " ");
appendText(getTypeParameterList(), indentLevel, buffer, " ");
appendText(getExtendsList(), indentLevel, buffer, " ");
appendText(getImplementsList(), indentLevel, buffer, " ");
buffer.append('{');
int newIndentLevel = indentLevel + getIndentSize();
List<PsiField> fields = getOwnFields();
List<PsiMethod> methods = getOwnMethods();
List<PsiClass> classes = getOwnInnerClasses();
if (!fields.isEmpty()) {
goNextLine(newIndentLevel, buffer);
for (int i = 0; i < fields.size(); i++) {
PsiField field = fields.get(i);
appendText(field, newIndentLevel, buffer);
if (field instanceof ClsEnumConstantImpl) {
if (i < fields.size() - 1 && fields.get(i + 1) instanceof ClsEnumConstantImpl) {
buffer.append(", ");
}
else {
buffer.append(';');
if (i < fields.size() - 1) {
buffer.append('\n');
goNextLine(newIndentLevel, buffer);
}
}
}
else if (i < fields.size() - 1) {
goNextLine(newIndentLevel, buffer);
}
}
}
else if (isEnum() && methods.size() + classes.size() > 0) {
goNextLine(newIndentLevel, buffer);
buffer.append(";");
}
if (!methods.isEmpty()) {
if (isEnum() || !fields.isEmpty()) {
buffer.append('\n');
}
goNextLine(newIndentLevel, buffer);
for (int i = 0; i < methods.size(); i++) {
appendText(methods.get(i), newIndentLevel, buffer);
if (i < methods.size() - 1) {
buffer.append('\n');
goNextLine(newIndentLevel, buffer);
}
}
}
if (!classes.isEmpty()) {
if (fields.size() + methods.size() > 0) {
buffer.append('\n');
}
goNextLine(newIndentLevel, buffer);
for (int i = 0; i < classes.size(); i++) {
appendText(classes.get(i), newIndentLevel, buffer);
if (i < classes.size() - 1) {
buffer.append('\n');
goNextLine(newIndentLevel, buffer);
}
}
}
goNextLine(indentLevel, buffer);
buffer.append('}');
}
@Override
public void setMirror(@NotNull TreeElement element) throws InvalidMirrorException {
setMirrorCheckingType(element, null);
PsiClass mirror = SourceTreeToPsiMap.treeToPsiNotNull(element);
setMirrorIfPresent(getDocComment(), mirror.getDocComment());
setMirror(getModifierList(), mirror.getModifierList());
setMirror(getNameIdentifier(), mirror.getNameIdentifier());
setMirror(getTypeParameterList(), mirror.getTypeParameterList());
setMirror(getExtendsList(), mirror.getExtendsList());
setMirror(getImplementsList(), mirror.getImplementsList());
if (mirror instanceof PsiExtensibleClass) {
PsiExtensibleClass extMirror = (PsiExtensibleClass)mirror;
setMirrors(getOwnFields(), extMirror.getOwnFields());
setMirrors(getOwnMethods(), extMirror.getOwnMethods());
setMirrors(getOwnInnerClasses(), extMirror.getOwnInnerClasses());
}
else {
setMirrors(getOwnFields(), mirror.getFields());
setMirrors(getOwnMethods(), mirror.getMethods());
setMirrors(getOwnInnerClasses(), mirror.getInnerClasses());
}
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor)visitor).visitClass(this);
}
else {
visitor.visitElement(this);
}
}
@NonNls
public String toString() {
return "PsiClass:" + getName();
}
@Override
public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
PsiElement lastParent,
@NotNull PsiElement place) {
if (isEnum()) {
if (!PsiClassImplUtil.processDeclarationsInEnum(processor, state, myInnersCache)) return false;
}
LanguageLevel level = processor instanceof MethodsProcessor ? ((MethodsProcessor)processor).getLanguageLevel() : PsiUtil.getLanguageLevel(place);
return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, level, false);
}
@Override
public PsiElement getScope() {
return getParent();
}
@Override
public boolean isInheritorDeep(PsiClass baseClass, PsiClass classToByPass) {
return InheritanceImplUtil.isInheritorDeep(this, baseClass, classToByPass);
}
@Override
public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
return InheritanceImplUtil.isInheritor(this, baseClass, checkDeep);
}
@Nullable
public PsiClass getSourceMirrorClass() {
final PsiClass delegate = getUserData(DELEGATE_KEY);
if (delegate instanceof ClsClassImpl) {
return ((ClsClassImpl)delegate).getSourceMirrorClass();
}
final String name = getName();
final PsiElement parent = getParent();
if (parent instanceof PsiFile) {
if (!(parent instanceof PsiClassOwner)) return null;
PsiClassOwner fileNavigationElement = (PsiClassOwner)parent.getNavigationElement();
if (fileNavigationElement == parent) return null;
for (PsiClass aClass : fileNavigationElement.getClasses()) {
if (name.equals(aClass.getName())) return aClass;
}
}
else if (parent != null) {
ClsClassImpl parentClass = (ClsClassImpl)parent;
PsiClass parentSourceMirror = parentClass.getSourceMirrorClass();
if (parentSourceMirror == null) return null;
PsiClass[] innerClasses = parentSourceMirror.getInnerClasses();
for (PsiClass innerClass : innerClasses) {
if (name.equals(innerClass.getName())) return innerClass;
}
}
else {
throw new PsiInvalidElementAccessException(this);
}
return null;
}
@Override
@NotNull
public PsiElement getNavigationElement() {
for (ClsCustomNavigationPolicy customNavigationPolicy : Extensions.getExtensions(ClsCustomNavigationPolicy.EP_NAME)) {
PsiElement navigationElement = customNavigationPolicy.getNavigationElement(this);
if (navigationElement != null) {
return navigationElement;
}
}
PsiClass aClass = getSourceMirrorClass();
if (aClass != null) {
return aClass.getNavigationElement();
}
if ("package-info".equals(getName())) {
PsiElement parent = getParent();
if (parent instanceof ClsFileImpl) {
PsiElement sourceFile = parent.getNavigationElement();
if (sourceFile instanceof PsiJavaFile) {
return sourceFile;
}
}
}
return this;
}
@Override
public ItemPresentation getPresentation() {
return ItemPresentationProviders.getItemPresentation(this);
}
@Override
public Icon getElementIcon(final int flags) {
return PsiClassImplUtil.getClassIcon(flags, this);
}
@Override
public boolean isEquivalentTo(final PsiElement another) {
return PsiClassImplUtil.isClassEquivalentTo(this, another);
}
@Override
@NotNull
public SearchScope getUseScope() {
return PsiClassImplUtil.getClassUseScope(this);
}
@Override
public PsiQualifiedNamedElement getContainer() {
final PsiFile file = getContainingFile();
final PsiDirectory dir;
return file == null ? null : (dir = file.getContainingDirectory()) == null
? null : JavaDirectoryService.getInstance().getPackage(dir);
}
@Override
public void putInfo(@NotNull Map<String, String> info) {
PsiClassImpl.putInfo(this, info);
}
@Override
protected boolean isVisibilitySupported() {
return true;
}
}