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