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
153 if (declaration != null) {
154 return !isTraitFakeOverride(declaration) ?
155 new KotlinLightMethodForDeclaration(myManager, method, declaration, KotlinWrappingLightClass.this) :
156 new KotlinLightMethodForTraitFakeOverride(myManager, method, declaration, KotlinWrappingLightClass.this);
157 }
158
159 return new KotlinNoOriginLightMethod(myManager, method, KotlinWrappingLightClass.this);
160 }
161 });
162 }
163
164 @Override
165 public boolean processDeclarations(
166 @NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place
167 ) {
168 if (isEnum()) {
169 if (!PsiClassImplUtil.processDeclarationsInEnum(processor, state, myInnersCache)) return false;
170 }
171
172 return super.processDeclarations(processor, state, lastParent, place);
173 }
174
175 @Override
176 public String getText() {
177 JetClassOrObject origin = getOrigin();
178 return origin == null ? null : origin.getText();
179 }
180
181 @NotNull
182 @Override
183 public Language getLanguage() {
184 return JetLanguage.INSTANCE;
185 }
186
187 private boolean isTraitFakeOverride(@NotNull JetDeclaration originMethodDeclaration) {
188 if (!(originMethodDeclaration instanceof JetNamedFunction ||
189 originMethodDeclaration instanceof JetPropertyAccessor ||
190 originMethodDeclaration instanceof JetProperty)) {
191 return false;
192 }
193
194 JetClassOrObject parentOfMethodOrigin = PsiTreeUtil.getParentOfType(originMethodDeclaration, JetClassOrObject.class);
195 JetClassOrObject thisClassDeclaration = getOrigin();
196
197 // Method was generated from declaration in some other trait
198 return (parentOfMethodOrigin != null && thisClassDeclaration != parentOfMethodOrigin && JetPsiUtil.isTrait(parentOfMethodOrigin));
199 }
200
201 @Override
202 public ItemPresentation getPresentation() {
203 return ItemPresentationProviders.getItemPresentation(this);
204 }
205 }