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.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.JetFile; 034 import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; 035 import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker; 036 import org.jetbrains.jet.lang.resolve.name.FqName; 037 import org.jetbrains.jet.plugin.JetLanguage; 038 039 import javax.swing.*; 040 import java.util.Collection; 041 import java.util.Collections; 042 import java.util.List; 043 044 public class KotlinLightClassForPackage extends KotlinWrappingLightClass 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<LightClassStubWithData> 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 List<PsiClass> getOwnInnerClasses() { 215 return Collections.emptyList(); 216 } 217 218 @NotNull 219 @Override 220 public PsiClass[] getAllInnerClasses() { 221 return PsiClass.EMPTY_ARRAY; 222 } 223 224 @NotNull 225 @Override 226 public PsiClassInitializer[] getInitializers() { 227 return PsiClassInitializer.EMPTY_ARRAY; 228 } 229 230 @Nullable 231 @Override 232 public PsiClass findInnerClassByName(@NonNls String name, boolean checkBases) { 233 return null; 234 } 235 236 @NotNull 237 @Override 238 public FqName getFqName() { 239 return packageClassFqName; 240 } 241 242 @Nullable 243 @Override 244 public String getName() { 245 return packageClassFqName.shortName().asString(); 246 } 247 248 @Nullable 249 @Override 250 public String getQualifiedName() { 251 return packageClassFqName.asString(); 252 } 253 254 @Override 255 public boolean isValid() { 256 return allValid(files); 257 } 258 259 @NotNull 260 @Override 261 public PsiElement copy() { 262 return new KotlinLightClassForPackage(getManager(), packageFqName, searchScope, files); 263 } 264 265 @NotNull 266 @Override 267 public PsiClass getDelegate() { 268 PsiClass psiClass = LightClassUtil.findClass(packageClassFqName, javaFileStub.getValue().getJavaFileStub()); 269 if (psiClass == null) { 270 throw new IllegalStateException("Package class was not found " + packageFqName); 271 } 272 return psiClass; 273 } 274 275 @NotNull 276 @Override 277 public PsiElement getNavigationElement() { 278 return files.iterator().next(); 279 } 280 281 @Override 282 public boolean isEquivalentTo(PsiElement another) { 283 return another instanceof PsiClass && Comparing.equal(((PsiClass) another).getQualifiedName(), getQualifiedName()); 284 } 285 286 @Override 287 public ItemPresentation getPresentation() { 288 return ItemPresentationProviders.getItemPresentation(this); 289 } 290 291 @Override 292 public Icon getElementIcon(int flags) { 293 throw new UnsupportedOperationException("This should be done byt JetIconProvider"); 294 } 295 296 @Override 297 public int hashCode() { 298 return hashCode; 299 } 300 301 private int computeHashCode() { 302 int result = getManager().hashCode(); 303 result = 31 * result + files.hashCode(); 304 result = 31 * result + packageFqName.hashCode(); 305 return result; 306 } 307 308 @Override 309 public boolean equals(Object obj) { 310 if (this == obj) return true; 311 if (obj == null || getClass() != obj.getClass()) { 312 return false; 313 } 314 315 KotlinLightClassForPackage lightClass = (KotlinLightClassForPackage) obj; 316 317 if (this.hashCode != lightClass.hashCode) return false; 318 if (getManager() != lightClass.getManager()) return false; 319 if (!files.equals(lightClass.files)) return false; 320 if (!packageFqName.equals(lightClass.packageFqName)) return false; 321 322 return true; 323 } 324 325 @Override 326 public String toString() { 327 try { 328 return KotlinLightClassForPackage.class.getSimpleName() + ":" + getQualifiedName(); 329 } 330 catch (Throwable e) { 331 return KotlinLightClassForPackage.class.getSimpleName() + ":" + e.toString(); 332 } 333 } 334 }