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.asJava;
018    
019    import com.intellij.lang.Language;
020    import com.intellij.navigation.ItemPresentation;
021    import com.intellij.navigation.ItemPresentationProviders;
022    import com.intellij.psi.*;
023    import com.intellij.psi.impl.PsiClassImplUtil;
024    import com.intellij.psi.impl.light.AbstractLightClass;
025    import com.intellij.psi.impl.source.ClassInnerStuffCache;
026    import com.intellij.psi.impl.source.PsiExtensibleClass;
027    import com.intellij.psi.scope.PsiScopeProcessor;
028    import com.intellij.psi.util.PsiTreeUtil;
029    import com.intellij.util.Function;
030    import com.intellij.util.containers.ContainerUtil;
031    import kotlin.KotlinPackage;
032    import kotlin.jvm.functions.Function1;
033    import org.jetbrains.annotations.NotNull;
034    import org.jetbrains.annotations.Nullable;
035    import org.jetbrains.kotlin.idea.JetLanguage;
036    import org.jetbrains.kotlin.name.FqName;
037    import org.jetbrains.kotlin.psi.*;
038    import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
039    
040    import java.util.List;
041    
042    public abstract class KotlinWrappingLightClass extends AbstractLightClass implements KotlinLightClass, PsiExtensibleClass {
043        private final ClassInnerStuffCache myInnersCache = new ClassInnerStuffCache(this);
044    
045        protected KotlinWrappingLightClass(PsiManager manager) {
046            super(manager, JetLanguage.INSTANCE);
047        }
048    
049        @Nullable
050        @Override
051        public abstract JetClassOrObject getOrigin();
052    
053        @NotNull
054        @Override
055        public abstract PsiClass getDelegate();
056    
057        @Override
058        @NotNull
059        public PsiField[] getFields() {
060            return myInnersCache.getFields();
061        }
062    
063        @Override
064        @NotNull
065        public PsiMethod[] getMethods() {
066            return myInnersCache.getMethods();
067        }
068    
069        @Override
070        @NotNull
071        public PsiMethod[] getConstructors() {
072            return myInnersCache.getConstructors();
073        }
074    
075        @Override
076        @NotNull
077        public PsiClass[] getInnerClasses() {
078            return myInnersCache.getInnerClasses();
079        }
080    
081        @Override
082        @NotNull
083        public PsiField[] getAllFields() {
084            return PsiClassImplUtil.getAllFields(this);
085        }
086    
087        @Override
088        @NotNull
089        public PsiMethod[] getAllMethods() {
090            return PsiClassImplUtil.getAllMethods(this);
091        }
092    
093        @Override
094        @NotNull
095        public PsiClass[] getAllInnerClasses() {
096            return PsiClassImplUtil.getAllInnerClasses(this);
097        }
098    
099        @Override
100        public PsiField findFieldByName(String name, boolean checkBases) {
101            return myInnersCache.findFieldByName(name, checkBases);
102        }
103    
104        @Override
105        @NotNull
106        public PsiMethod[] findMethodsByName(String name, boolean checkBases) {
107            return myInnersCache.findMethodsByName(name, checkBases);
108        }
109    
110        @Override
111        public PsiClass findInnerClassByName(String name, boolean checkBases) {
112            return myInnersCache.findInnerClassByName(name, checkBases);
113        }
114    
115        /**
116         * @see org.jetbrains.kotlin.codegen.binding.CodegenBinding#ENUM_ENTRY_CLASS_NEED_SUBCLASS
117          */
118        @NotNull
119        @Override
120        public List<PsiField> getOwnFields() {
121            return ContainerUtil.map(getDelegate().getFields(), new Function<PsiField, PsiField>() {
122                @Override
123                public PsiField fun(PsiField field) {
124                    JetDeclaration declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(field);
125                    if (declaration instanceof JetEnumEntry) {
126                        assert field instanceof PsiEnumConstant : "Field delegate should be an enum constant (" + field.getName() + "):\n" +
127                                                                  PsiUtilPackage.getElementTextWithContext(declaration);
128                        JetEnumEntry enumEntry = (JetEnumEntry) declaration;
129                        PsiEnumConstant enumConstant = (PsiEnumConstant) field;
130                        FqName enumConstantFqName = new FqName(getFqName().asString() + "." + enumEntry.getName());
131                        KotlinLightClassForEnumEntry initializingClass =
132                                enumEntry.getDeclarations().isEmpty()
133                                ? null
134                                : new KotlinLightClassForEnumEntry(myManager, enumConstantFqName, enumEntry, enumConstant);
135                        return new KotlinLightEnumConstant(myManager, enumEntry, enumConstant, KotlinWrappingLightClass.this, initializingClass);
136                    }
137                    if (declaration != null) {
138                        return new KotlinLightFieldForDeclaration(myManager, declaration, field, KotlinWrappingLightClass.this);
139                    }
140                    return new KotlinNoOriginLightField(myManager, field, KotlinWrappingLightClass.this);
141                }
142            });
143        }
144    
145        @NotNull
146        @Override
147        public List<PsiMethod> getOwnMethods() {
148            return KotlinPackage.map(getDelegate().getMethods(), new Function1<PsiMethod, PsiMethod>() {
149                @Override
150                public PsiMethod invoke(PsiMethod method) {
151                    JetDeclaration declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(method);
152                    if (declaration instanceof JetPropertyAccessor) {
153                        declaration = PsiTreeUtil.getParentOfType(declaration, JetProperty.class);
154                    }
155    
156                    if (declaration != null) {
157                        return !isTraitFakeOverride(declaration) ?
158                               new KotlinLightMethodForDeclaration(myManager, method, declaration, KotlinWrappingLightClass.this) :
159                               new KotlinLightMethodForTraitFakeOverride(myManager, method, declaration, KotlinWrappingLightClass.this);
160                    }
161    
162                    return new KotlinNoOriginLightMethod(myManager, method, KotlinWrappingLightClass.this);
163                }
164            });
165        }
166    
167        @Override
168        public boolean processDeclarations(
169                @NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place
170        ) {
171            if (isEnum()) {
172                if (!PsiClassImplUtil.processDeclarationsInEnum(processor, state, myInnersCache)) return false;
173            }
174    
175            return super.processDeclarations(processor, state, lastParent, place);
176        }
177    
178        @Override
179        public String getText() {
180            JetClassOrObject origin = getOrigin();
181            return origin == null ? null : origin.getText();
182        }
183    
184        @NotNull
185        @Override
186        public Language getLanguage() {
187            return JetLanguage.INSTANCE;
188        }
189    
190        private boolean isTraitFakeOverride(@NotNull JetDeclaration originMethodDeclaration) {
191            if (!(originMethodDeclaration instanceof JetNamedFunction ||
192                  originMethodDeclaration instanceof JetPropertyAccessor ||
193                  originMethodDeclaration instanceof JetProperty)) {
194                return false;
195            }
196    
197            JetClassOrObject parentOfMethodOrigin = PsiTreeUtil.getParentOfType(originMethodDeclaration, JetClassOrObject.class);
198            JetClassOrObject thisClassDeclaration = getOrigin();
199    
200            // Method was generated from declaration in some other trait
201            return (parentOfMethodOrigin != null && thisClassDeclaration != parentOfMethodOrigin && JetPsiUtil.isTrait(parentOfMethodOrigin));
202        }
203    
204        @Override
205        public ItemPresentation getPresentation() {
206            return ItemPresentationProviders.getItemPresentation(this);
207        }
208    
209        @Override
210        public abstract boolean equals(Object obj);
211    
212        @Override
213        public abstract int hashCode();
214    }