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.LightEmptyImplementsList; 026 import com.intellij.psi.impl.light.LightModifierList; 027 import com.intellij.psi.javadoc.PsiDocComment; 028 import com.intellij.psi.search.GlobalSearchScope; 029 import com.intellij.psi.util.CachedValue; 030 import com.intellij.psi.util.CachedValuesManager; 031 import org.jetbrains.annotations.NonNls; 032 import org.jetbrains.annotations.NotNull; 033 import org.jetbrains.annotations.Nullable; 034 import org.jetbrains.jet.lang.psi.JetFile; 035 import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker; 036 import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; 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 KotlinLightClass, 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<PsiJavaFileStub> javaFileStub; 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 stubProvider = 071 KotlinJavaFileStubProvider.createForPackageClass(getProject(), packageFqName, searchScope); 072 this.javaFileStub = 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 PsiModifierList getModifierList() { 098 return modifierList; 099 } 100 101 @Override 102 public boolean hasModifierProperty(@NonNls @NotNull String name) { 103 return modifierList.hasModifierProperty(name); 104 } 105 106 @Override 107 public boolean isDeprecated() { 108 return false; 109 } 110 111 @Override 112 public boolean isInterface() { 113 return false; 114 } 115 116 @Override 117 public boolean isAnnotationType() { 118 return false; 119 } 120 121 @Override 122 public boolean isEnum() { 123 return false; 124 } 125 126 @Nullable 127 @Override 128 public PsiClass getContainingClass() { 129 return null; 130 } 131 132 @Override 133 public boolean hasTypeParameters() { 134 return false; 135 } 136 137 @NotNull 138 @Override 139 public PsiTypeParameter[] getTypeParameters() { 140 return PsiTypeParameter.EMPTY_ARRAY; 141 } 142 143 @Nullable 144 @Override 145 public PsiTypeParameterList getTypeParameterList() { 146 return null; 147 } 148 149 @Nullable 150 @Override 151 public PsiDocComment getDocComment() { 152 return null; 153 } 154 155 @Nullable 156 @Override 157 public PsiReferenceList getImplementsList() { 158 return implementsList; 159 } 160 161 @NotNull 162 @Override 163 public PsiClassType[] getImplementsListTypes() { 164 return PsiClassType.EMPTY_ARRAY; 165 } 166 167 @Nullable 168 @Override 169 public PsiReferenceList getExtendsList() { 170 // TODO: Find a way to return just Object 171 return super.getExtendsList(); 172 } 173 174 @NotNull 175 @Override 176 public PsiClassType[] getExtendsListTypes() { 177 // TODO see getExtendsList() 178 return super.getExtendsListTypes(); 179 } 180 181 @Nullable 182 @Override 183 public PsiClass getSuperClass() { 184 // TODO see getExtendsList() 185 return super.getSuperClass(); 186 } 187 188 @NotNull 189 @Override 190 public PsiClass[] getSupers() { 191 // TODO see getExtendsList() 192 return super.getSupers(); 193 } 194 195 @NotNull 196 @Override 197 public PsiClassType[] getSuperTypes() { 198 // TODO see getExtendsList() 199 return super.getSuperTypes(); 200 } 201 202 @Override 203 public PsiClass[] getInterfaces() { 204 return PsiClass.EMPTY_ARRAY; 205 } 206 207 @NotNull 208 @Override 209 public PsiClass[] getInnerClasses() { 210 return PsiClass.EMPTY_ARRAY; 211 } 212 213 @NotNull 214 @Override 215 public List<PsiClass> getOwnInnerClasses() { 216 return Collections.emptyList(); 217 } 218 219 @NotNull 220 @Override 221 public PsiClass[] getAllInnerClasses() { 222 return PsiClass.EMPTY_ARRAY; 223 } 224 225 @NotNull 226 @Override 227 public PsiClassInitializer[] getInitializers() { 228 return PsiClassInitializer.EMPTY_ARRAY; 229 } 230 231 @Nullable 232 @Override 233 public PsiClass findInnerClassByName(@NonNls String name, boolean checkBases) { 234 return null; 235 } 236 237 @NotNull 238 @Override 239 public FqName getFqName() { 240 return packageClassFqName; 241 } 242 243 @Nullable 244 @Override 245 public String getName() { 246 return packageClassFqName.shortName().asString(); 247 } 248 249 @Nullable 250 @Override 251 public String getQualifiedName() { 252 return packageClassFqName.asString(); 253 } 254 255 @Override 256 public boolean isValid() { 257 return allValid(files); 258 } 259 260 @NotNull 261 @Override 262 public PsiElement copy() { 263 return new KotlinLightClassForPackage(getManager(), packageFqName, searchScope, files); 264 } 265 266 @NotNull 267 @Override 268 public PsiClass getDelegate() { 269 PsiClass psiClass = LightClassUtil.findClass(packageClassFqName, javaFileStub.getValue()); 270 if (psiClass == null) { 271 throw new IllegalStateException("Package class was not found " + packageFqName); 272 } 273 return psiClass; 274 } 275 276 @NotNull 277 @Override 278 public PsiElement getNavigationElement() { 279 return files.iterator().next(); 280 } 281 282 @Override 283 public boolean isEquivalentTo(PsiElement another) { 284 return another instanceof PsiClass && Comparing.equal(((PsiClass) another).getQualifiedName(), getQualifiedName()); 285 } 286 287 @Override 288 public ItemPresentation getPresentation() { 289 return ItemPresentationProviders.getItemPresentation(this); 290 } 291 292 @Override 293 public Icon getElementIcon(int flags) { 294 throw new UnsupportedOperationException("This should be done byt JetIconProvider"); 295 } 296 297 @Override 298 public int hashCode() { 299 return hashCode; 300 } 301 302 private int computeHashCode() { 303 int result = getManager().hashCode(); 304 result = 31 * result + files.hashCode(); 305 result = 31 * result + packageFqName.hashCode(); 306 return result; 307 } 308 309 @Override 310 public boolean equals(Object obj) { 311 if (this == obj) return true; 312 if (obj == null || getClass() != obj.getClass()) { 313 return false; 314 } 315 316 KotlinLightClassForPackage lightClass = (KotlinLightClassForPackage) obj; 317 318 if (this.hashCode != lightClass.hashCode) return false; 319 if (getManager() != lightClass.getManager()) return false; 320 if (!files.equals(lightClass.files)) return false; 321 if (!packageFqName.equals(lightClass.packageFqName)) return false; 322 323 return true; 324 } 325 326 @Override 327 public String toString() { 328 try { 329 return KotlinLightClassForPackage.class.getSimpleName() + ":" + getQualifiedName(); 330 } 331 catch (Throwable e) { 332 return KotlinLightClassForPackage.class.getSimpleName() + ":" + e.toString(); 333 } 334 } 335 }