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.collections.ArraysKt;
032    import kotlin.jvm.functions.Function1;
033    import org.jetbrains.annotations.NotNull;
034    import org.jetbrains.annotations.Nullable;
035    import org.jetbrains.kotlin.idea.KotlinLanguage;
036    import org.jetbrains.kotlin.psi.KtClassOrObject;
037    import org.jetbrains.kotlin.psi.KtDeclaration;
038    import org.jetbrains.kotlin.psi.KtProperty;
039    import org.jetbrains.kotlin.psi.KtPropertyAccessor;
040    
041    import java.util.List;
042    
043    public abstract class KtWrappingLightClass extends AbstractLightClass implements KtLightClass, PsiExtensibleClass {
044        private final ClassInnerStuffCache myInnersCache = new ClassInnerStuffCache(this);
045    
046        protected KtWrappingLightClass(PsiManager manager) {
047            super(manager, KotlinLanguage.INSTANCE);
048        }
049    
050        @Nullable
051        @Override
052        public abstract KtClassOrObject 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                    LightMemberOrigin origin = ClsWrapperStubPsiFactory.getMemberOrigin(field);
126                    return KtLightFieldImpl.Factory.create(origin != null ? origin.getOriginalElement() : null, field, KtWrappingLightClass.this);
127                }
128            });
129        }
130    
131        @NotNull
132        @Override
133        public List<PsiMethod> getOwnMethods() {
134            return ArraysKt.map(getDelegate().getMethods(), new Function1<PsiMethod, PsiMethod>() {
135                @Override
136                public PsiMethod invoke(PsiMethod method) {
137                    LightMemberOrigin origin = ClsWrapperStubPsiFactory.getMemberOrigin(method);
138                    KtDeclaration originalElement = origin != null ? origin.getOriginalElement() : null;
139                    if (originalElement instanceof KtPropertyAccessor) {
140                        //noinspection ConstantConditions
141                        origin = origin.copy(PsiTreeUtil.getParentOfType(originalElement, KtProperty.class), origin.getOriginKind());
142                    }
143    
144                    return KtLightMethodImpl.Factory.create(method, origin, KtWrappingLightClass.this);
145                }
146            });
147        }
148    
149        @Override
150        public boolean processDeclarations(
151                @NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place
152        ) {
153            if (isEnum()) {
154                if (!PsiClassImplUtil.processDeclarationsInEnum(processor, state, myInnersCache)) return false;
155            }
156    
157            return super.processDeclarations(processor, state, lastParent, place);
158        }
159    
160        @Override
161        public String getText() {
162            KtClassOrObject origin = getOrigin();
163            return origin == null ? "" : origin.getText();
164        }
165    
166        @NotNull
167        @Override
168        public Language getLanguage() {
169            return KotlinLanguage.INSTANCE;
170        }
171    
172        @Override
173        public ItemPresentation getPresentation() {
174            return ItemPresentationProviders.getItemPresentation(this);
175        }
176    
177        @Override
178        public abstract boolean equals(Object obj);
179    
180        @Override
181        public abstract int hashCode();
182    
183        @Override
184        public PsiElement getContext() {
185            return getParent();
186        }
187    }