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