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