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