001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.load.java.structure.impl;
018    
019    import com.intellij.psi.*;
020    import kotlin.collections.ArraysKt;
021    import kotlin.collections.CollectionsKt;
022    import kotlin.jvm.functions.Function1;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.kotlin.asJava.KtLightClassMarker;
026    import org.jetbrains.kotlin.descriptors.Visibility;
027    import org.jetbrains.kotlin.load.java.structure.*;
028    import org.jetbrains.kotlin.name.FqName;
029    import org.jetbrains.kotlin.name.Name;
030    import org.jetbrains.kotlin.name.SpecialNames;
031    
032    import java.util.Collection;
033    import java.util.List;
034    
035    import static org.jetbrains.kotlin.load.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.*;
036    
037    public class JavaClassImpl extends JavaClassifierImpl<PsiClass> implements JavaClass, JavaAnnotationOwnerImpl, JavaModifierListOwnerImpl {
038        public JavaClassImpl(@NotNull PsiClass psiClass) {
039            super(psiClass);
040            assert !(psiClass instanceof PsiTypeParameter)
041                    : "PsiTypeParameter should be wrapped in JavaTypeParameter, not JavaClass: use JavaClassifier.create()";
042        }
043    
044        @Override
045        @NotNull
046        public Collection<JavaClass> getInnerClasses() {
047            return classes(getPsi().getInnerClasses());
048        }
049    
050        @Override
051        @Nullable
052        public FqName getFqName() {
053            String qualifiedName = getPsi().getQualifiedName();
054            return qualifiedName == null ? null : new FqName(qualifiedName);
055        }
056    
057        @NotNull
058        @Override
059        public Name getName() {
060            return SpecialNames.safeIdentifier(getPsi().getName());
061        }
062    
063        @Override
064        public boolean isInterface() {
065            return getPsi().isInterface();
066        }
067    
068        @Override
069        public boolean isAnnotationType() {
070            return getPsi().isAnnotationType();
071        }
072    
073        @Override
074        public boolean isEnum() {
075            return getPsi().isEnum();
076        }
077    
078        @Override
079        @Nullable
080        public JavaClassImpl getOuterClass() {
081            PsiClass outer = getPsi().getContainingClass();
082            return outer == null ? null : new JavaClassImpl(outer);
083        }
084    
085        @NotNull
086        @Override
087        public List<JavaTypeParameter> getTypeParameters() {
088            return typeParameters(getPsi().getTypeParameters());
089        }
090    
091        @Override
092        @NotNull
093        public Collection<JavaClassifierType> getSupertypes() {
094            return classifierTypes(getPsi().getSuperTypes());
095        }
096    
097        @Override
098        @NotNull
099        public Collection<JavaMethod> getMethods() {
100            // We apply distinct here because PsiClass#getMethods() can return duplicate PSI methods, for example in Lombok (see KT-11778)
101            return CollectionsKt.distinct(methods(ArraysKt.filter(getPsi().getMethods(), new Function1<PsiMethod, Boolean>() {
102                @Override
103                public Boolean invoke(PsiMethod method) {
104                    // Return type seems to be null for example for the 'clone' Groovy method generated by @AutoClone (see EA-73795)
105                    return !method.isConstructor() && method.getReturnType() != null;
106                }
107            })));
108        }
109    
110        @Override
111        @NotNull
112        public Collection<JavaField> getFields() {
113            // ex. Android plugin generates LightFields for resources started from '.' (.DS_Store file etc)
114            return fields(ArraysKt.filter(getPsi().getFields(), new Function1<PsiField, Boolean>() {
115                @Override
116                public Boolean invoke(PsiField field) {
117                    String name = field.getName();
118                    return name != null && Name.isValidIdentifier(name);
119                }
120            }));
121        }
122    
123        @Override
124        @NotNull
125        public Collection<JavaConstructor> getConstructors() {
126            return constructors(ArraysKt.filter(getPsi().getConstructors(), new Function1<PsiMethod, Boolean>() {
127                @Override
128                public Boolean invoke(PsiMethod method) {
129                    // See for example org.jetbrains.plugins.scala.lang.psi.light.ScFunctionWrapper,
130                    // which is present in getConstructors(), but its isConstructor() returns false
131                    return method.isConstructor();
132                }
133            }));
134        }
135    
136        @Override
137        public boolean isAbstract() {
138            return JavaElementUtil.isAbstract(this);
139        }
140    
141        @Override
142        public boolean isStatic() {
143            return JavaElementUtil.isStatic(this);
144        }
145    
146        @Override
147        public boolean isFinal() {
148            return JavaElementUtil.isFinal(this);
149        }
150    
151        @NotNull
152        @Override
153        public Visibility getVisibility() {
154            return JavaElementUtil.getVisibility(this);
155        }
156    
157        @Nullable
158        @Override
159        public LightClassOriginKind getLightClassOriginKind() {
160            PsiClass psiClass = getPsi();
161            if (psiClass instanceof KtLightClassMarker) {
162                return ((KtLightClassMarker) psiClass).getOriginKind();
163            }
164            return null;
165        }
166    
167        @Nullable
168        @Override
169        public PsiAnnotationOwner getAnnotationOwnerPsi() {
170            return getPsi().getModifierList();
171        }
172    }