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 }