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