001 /* 002 * Copyright 2010-2013 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.google.common.collect.Sets; 020 import com.intellij.navigation.ItemPresentation; 021 import com.intellij.navigation.ItemPresentationProviders; 022 import com.intellij.openapi.util.Comparing; 023 import com.intellij.psi.*; 024 import com.intellij.psi.impl.java.stubs.PsiJavaFileStub; 025 import com.intellij.psi.impl.light.AbstractLightClass; 026 import com.intellij.psi.impl.light.LightEmptyImplementsList; 027 import com.intellij.psi.impl.light.LightModifierList; 028 import com.intellij.psi.javadoc.PsiDocComment; 029 import com.intellij.psi.search.GlobalSearchScope; 030 import com.intellij.psi.util.CachedValue; 031 import com.intellij.psi.util.CachedValuesManager; 032 import org.jetbrains.annotations.NonNls; 033 import org.jetbrains.annotations.NotNull; 034 import org.jetbrains.annotations.Nullable; 035 import org.jetbrains.jet.lang.psi.JetFile; 036 import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker; 037 import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; 038 import org.jetbrains.jet.lang.resolve.name.FqName; 039 import org.jetbrains.jet.plugin.JetLanguage; 040 041 import javax.swing.*; 042 import java.util.Collection; 043 044 public class KotlinLightClassForPackage extends AbstractLightClass implements KotlinLightClass, JetJavaMirrorMarker { 045 private final FqName packageFqName; 046 private final FqName packageClassFqName; // derived from packageFqName 047 private final GlobalSearchScope searchScope; 048 private final Collection<JetFile> files; 049 private final int hashCode; 050 private final CachedValue<PsiJavaFileStub> javaFileStub; 051 private final PsiModifierList modifierList; 052 private final LightEmptyImplementsList implementsList; 053 054 private KotlinLightClassForPackage( 055 @NotNull PsiManager manager, 056 @NotNull FqName packageFqName, 057 @NotNull GlobalSearchScope searchScope, 058 @NotNull Collection<JetFile> files 059 ) { 060 super(manager, JetLanguage.INSTANCE); 061 this.modifierList = new LightModifierList(manager, JetLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL); 062 this.implementsList = new LightEmptyImplementsList(manager); 063 this.packageFqName = packageFqName; 064 this.packageClassFqName = PackageClassUtils.getPackageClassFqName(packageFqName); 065 this.searchScope = searchScope; 066 assert !files.isEmpty() : "No files for package " + packageFqName; 067 this.files = Sets.newHashSet(files); // needed for hashCode 068 this.hashCode = computeHashCode(); 069 KotlinJavaFileStubProvider stubProvider = 070 KotlinJavaFileStubProvider.createForPackageClass(getProject(), packageFqName, searchScope); 071 this.javaFileStub = CachedValuesManager.getManager(getProject()).createCachedValue(stubProvider, /*trackValue = */false); 072 } 073 074 @Nullable 075 public static KotlinLightClassForPackage create( 076 @NotNull PsiManager manager, 077 @NotNull FqName qualifiedName, 078 @NotNull GlobalSearchScope searchScope, 079 @NotNull Collection<JetFile> files // this is redundant, but computing it multiple times is costly 080 ) { 081 for (JetFile file : files) { 082 if (LightClassUtil.belongsToKotlinBuiltIns(file)) return null; 083 } 084 return new KotlinLightClassForPackage(manager, qualifiedName, searchScope, files); 085 } 086 087 private static boolean allValid(Collection<JetFile> files) { 088 for (JetFile file : files) { 089 if (!file.isValid()) return false; 090 } 091 return true; 092 } 093 094 @Nullable 095 @Override 096 public PsiModifierList getModifierList() { 097 return modifierList; 098 } 099 100 @Override 101 public boolean hasModifierProperty(@NonNls @NotNull String name) { 102 return modifierList.hasModifierProperty(name); 103 } 104 105 @Override 106 public boolean isDeprecated() { 107 return false; 108 } 109 110 @Override 111 public boolean isInterface() { 112 return false; 113 } 114 115 @Override 116 public boolean isAnnotationType() { 117 return false; 118 } 119 120 @Override 121 public boolean isEnum() { 122 return false; 123 } 124 125 @Nullable 126 @Override 127 public PsiClass getContainingClass() { 128 return null; 129 } 130 131 @Override 132 public boolean hasTypeParameters() { 133 return false; 134 } 135 136 @NotNull 137 @Override 138 public PsiTypeParameter[] getTypeParameters() { 139 return PsiTypeParameter.EMPTY_ARRAY; 140 } 141 142 @Nullable 143 @Override 144 public PsiTypeParameterList getTypeParameterList() { 145 return null; 146 } 147 148 @Nullable 149 @Override 150 public PsiDocComment getDocComment() { 151 return null; 152 } 153 154 @Nullable 155 @Override 156 public PsiReferenceList getImplementsList() { 157 return implementsList; 158 } 159 160 @NotNull 161 @Override 162 public PsiClassType[] getImplementsListTypes() { 163 return PsiClassType.EMPTY_ARRAY; 164 } 165 166 @Nullable 167 @Override 168 public PsiReferenceList getExtendsList() { 169 // TODO: Find a way to return just Object 170 return super.getExtendsList(); 171 } 172 173 @NotNull 174 @Override 175 public PsiClassType[] getExtendsListTypes() { 176 // TODO see getExtendsList() 177 return super.getExtendsListTypes(); 178 } 179 180 @Nullable 181 @Override 182 public PsiClass getSuperClass() { 183 // TODO see getExtendsList() 184 return super.getSuperClass(); 185 } 186 187 @NotNull 188 @Override 189 public PsiClass[] getSupers() { 190 // TODO see getExtendsList() 191 return super.getSupers(); 192 } 193 194 @NotNull 195 @Override 196 public PsiClassType[] getSuperTypes() { 197 // TODO see getExtendsList() 198 return super.getSuperTypes(); 199 } 200 201 @Override 202 public PsiClass[] getInterfaces() { 203 return PsiClass.EMPTY_ARRAY; 204 } 205 206 @NotNull 207 @Override 208 public PsiClass[] getInnerClasses() { 209 return PsiClass.EMPTY_ARRAY; 210 } 211 212 @NotNull 213 @Override 214 public PsiClassInitializer[] getInitializers() { 215 return PsiClassInitializer.EMPTY_ARRAY; 216 } 217 218 @NotNull 219 @Override 220 public PsiClass[] getAllInnerClasses() { 221 return PsiClass.EMPTY_ARRAY; 222 } 223 224 @Nullable 225 @Override 226 public PsiClass findInnerClassByName(@NonNls String name, boolean checkBases) { 227 return null; 228 } 229 230 @NotNull 231 @Override 232 public FqName getFqName() { 233 return packageClassFqName; 234 } 235 236 @Nullable 237 @Override 238 public String getName() { 239 return packageClassFqName.shortName().asString(); 240 } 241 242 @Nullable 243 @Override 244 public String getQualifiedName() { 245 return packageClassFqName.asString(); 246 } 247 248 @Override 249 public boolean isValid() { 250 return allValid(files); 251 } 252 253 @NotNull 254 @Override 255 public PsiElement copy() { 256 return new KotlinLightClassForPackage(getManager(), packageFqName, searchScope, files); 257 } 258 259 @NotNull 260 @Override 261 public PsiClass getDelegate() { 262 PsiClass psiClass = LightClassUtil.findClass(packageClassFqName, javaFileStub.getValue()); 263 if (psiClass == null) { 264 throw new IllegalStateException("Package class was not found " + packageFqName); 265 } 266 return psiClass; 267 } 268 269 @NotNull 270 @Override 271 public PsiElement getNavigationElement() { 272 return files.iterator().next(); 273 } 274 275 @Override 276 public boolean isEquivalentTo(PsiElement another) { 277 return another instanceof PsiClass && Comparing.equal(((PsiClass) another).getQualifiedName(), getQualifiedName()); 278 } 279 280 @Override 281 public ItemPresentation getPresentation() { 282 return ItemPresentationProviders.getItemPresentation(this); 283 } 284 285 @Override 286 public Icon getElementIcon(int flags) { 287 throw new UnsupportedOperationException("This should be done byt JetIconProvider"); 288 } 289 290 @Override 291 public int hashCode() { 292 return hashCode; 293 } 294 295 private int computeHashCode() { 296 int result = getManager().hashCode(); 297 result = 31 * result + files.hashCode(); 298 result = 31 * result + packageFqName.hashCode(); 299 return result; 300 } 301 302 @Override 303 public boolean equals(Object obj) { 304 if (this == obj) return true; 305 if (obj == null || getClass() != obj.getClass()) { 306 return false; 307 } 308 309 KotlinLightClassForPackage lightClass = (KotlinLightClassForPackage) obj; 310 311 if (this.hashCode != lightClass.hashCode) return false; 312 if (getManager() != lightClass.getManager()) return false; 313 if (!files.equals(lightClass.files)) return false; 314 if (!packageFqName.equals(lightClass.packageFqName)) return false; 315 316 return true; 317 } 318 319 @Override 320 public String toString() { 321 try { 322 return KotlinLightClassForPackage.class.getSimpleName() + ":" + getQualifiedName(); 323 } 324 catch (Throwable e) { 325 return KotlinLightClassForPackage.class.getSimpleName() + ":" + e.toString(); 326 } 327 } 328 }