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.light.LightField; 026 import com.intellij.psi.impl.light.LightMethod; 027 import com.intellij.psi.impl.source.ClassInnerStuffCache; 028 import com.intellij.psi.impl.source.PsiExtensibleClass; 029 import com.intellij.psi.scope.PsiScopeProcessor; 030 import com.intellij.psi.util.PsiTreeUtil; 031 import com.intellij.util.Function; 032 import com.intellij.util.containers.ContainerUtil; 033 import kotlin.Function1; 034 import kotlin.KotlinPackage; 035 import org.jetbrains.annotations.NotNull; 036 import org.jetbrains.annotations.Nullable; 037 import org.jetbrains.kotlin.idea.JetLanguage; 038 import org.jetbrains.kotlin.name.FqName; 039 import org.jetbrains.kotlin.psi.*; 040 041 import java.util.List; 042 043 public abstract class KotlinWrappingLightClass extends AbstractLightClass implements KotlinLightClass, PsiExtensibleClass { 044 private final ClassInnerStuffCache myInnersCache = new ClassInnerStuffCache(this); 045 046 protected KotlinWrappingLightClass(PsiManager manager) { 047 super(manager, JetLanguage.INSTANCE); 048 } 049 050 @Nullable 051 @Override 052 public abstract JetClassOrObject 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 JetDeclaration declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(field); 126 if (declaration instanceof JetEnumEntry) { 127 assert field instanceof PsiEnumConstant : "Field delegate should be an enum constant (" + field.getName() + "):\n" + 128 JetPsiUtil.getElementTextWithContext(declaration); 129 JetEnumEntry enumEntry = (JetEnumEntry) declaration; 130 PsiEnumConstant enumConstant = (PsiEnumConstant) field; 131 FqName enumConstantFqName = new FqName(getFqName().asString() + "." + enumEntry.getName()); 132 KotlinLightClassForEnumEntry initializingClass = 133 enumEntry.getDeclarations().isEmpty() 134 ? null 135 : new KotlinLightClassForEnumEntry(myManager, enumConstantFqName, enumEntry, enumConstant); 136 return new KotlinLightEnumConstant(myManager, enumEntry, enumConstant, KotlinWrappingLightClass.this, initializingClass); 137 } 138 if (declaration != null) { 139 return new KotlinLightFieldForDeclaration(myManager, declaration, field, KotlinWrappingLightClass.this); 140 } 141 return new LightField(myManager, field, KotlinWrappingLightClass.this); 142 } 143 }); 144 } 145 146 @NotNull 147 @Override 148 public List<PsiMethod> getOwnMethods() { 149 return KotlinPackage.map(getDelegate().getMethods(), new Function1<PsiMethod, PsiMethod>() { 150 @Override 151 public PsiMethod invoke(PsiMethod method) { 152 JetDeclaration declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(method); 153 154 if (declaration != null) { 155 return !isTraitFakeOverride(declaration) ? 156 new KotlinLightMethodForDeclaration(myManager, method, declaration, KotlinWrappingLightClass.this) : 157 new KotlinLightMethodForTraitFakeOverride(myManager, method, declaration, KotlinWrappingLightClass.this); 158 } 159 160 return new LightMethod(myManager, method, KotlinWrappingLightClass.this); 161 } 162 }); 163 } 164 165 @Override 166 public boolean processDeclarations( 167 @NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place 168 ) { 169 if (isEnum()) { 170 if (!PsiClassImplUtil.processDeclarationsInEnum(processor, state, myInnersCache)) return false; 171 } 172 173 return super.processDeclarations(processor, state, lastParent, place); 174 } 175 176 @Override 177 public String getText() { 178 JetClassOrObject origin = getOrigin(); 179 return origin == null ? null : origin.getText(); 180 } 181 182 @NotNull 183 @Override 184 public Language getLanguage() { 185 return JetLanguage.INSTANCE; 186 } 187 188 private boolean isTraitFakeOverride(@NotNull JetDeclaration originMethodDeclaration) { 189 if (!(originMethodDeclaration instanceof JetNamedFunction || 190 originMethodDeclaration instanceof JetPropertyAccessor || 191 originMethodDeclaration instanceof JetProperty)) { 192 return false; 193 } 194 195 JetClassOrObject parentOfMethodOrigin = PsiTreeUtil.getParentOfType(originMethodDeclaration, JetClassOrObject.class); 196 JetClassOrObject thisClassDeclaration = getOrigin(); 197 198 // Method was generated from declaration in some other trait 199 return (parentOfMethodOrigin != null && thisClassDeclaration != parentOfMethodOrigin && JetPsiUtil.isTrait(parentOfMethodOrigin)); 200 } 201 202 @Override 203 public ItemPresentation getPresentation() { 204 return ItemPresentationProviders.getItemPresentation(this); 205 } 206 }