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    
153                    if (declaration != null) {
154                        return !isTraitFakeOverride(declaration) ?
155                               new KotlinLightMethodForDeclaration(myManager, method, declaration, KotlinWrappingLightClass.this) :
156                               new KotlinLightMethodForTraitFakeOverride(myManager, method, declaration, KotlinWrappingLightClass.this);
157                    }
158    
159                    return new KotlinNoOriginLightMethod(myManager, method, KotlinWrappingLightClass.this);
160                }
161            });
162        }
163    
164        @Override
165        public boolean processDeclarations(
166                @NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place
167        ) {
168            if (isEnum()) {
169                if (!PsiClassImplUtil.processDeclarationsInEnum(processor, state, myInnersCache)) return false;
170            }
171    
172            return super.processDeclarations(processor, state, lastParent, place);
173        }
174    
175        @Override
176        public String getText() {
177            JetClassOrObject origin = getOrigin();
178            return origin == null ? null : origin.getText();
179        }
180    
181        @NotNull
182        @Override
183        public Language getLanguage() {
184            return JetLanguage.INSTANCE;
185        }
186    
187        private boolean isTraitFakeOverride(@NotNull JetDeclaration originMethodDeclaration) {
188            if (!(originMethodDeclaration instanceof JetNamedFunction ||
189                  originMethodDeclaration instanceof JetPropertyAccessor ||
190                  originMethodDeclaration instanceof JetProperty)) {
191                return false;
192            }
193    
194            JetClassOrObject parentOfMethodOrigin = PsiTreeUtil.getParentOfType(originMethodDeclaration, JetClassOrObject.class);
195            JetClassOrObject thisClassDeclaration = getOrigin();
196    
197            // Method was generated from declaration in some other trait
198            return (parentOfMethodOrigin != null && thisClassDeclaration != parentOfMethodOrigin && JetPsiUtil.isTrait(parentOfMethodOrigin));
199        }
200    
201        @Override
202        public ItemPresentation getPresentation() {
203            return ItemPresentationProviders.getItemPresentation(this);
204        }
205    }