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 }