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