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.PsiClass; 024 import com.intellij.psi.PsiElement; 025 import com.intellij.psi.PsiManager; 026 import com.intellij.psi.impl.java.stubs.PsiJavaFileStub; 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.NotNull; 031 import org.jetbrains.annotations.Nullable; 032 import org.jetbrains.jet.lang.psi.JetFile; 033 import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker; 034 import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; 035 import org.jetbrains.jet.lang.resolve.name.FqName; 036 037 import javax.swing.*; 038 import java.util.Collection; 039 040 public class KotlinLightClassForPackage extends KotlinLightClassForPackageBase implements KotlinLightClass, JetJavaMirrorMarker { 041 @Nullable 042 public static KotlinLightClassForPackage create( 043 @NotNull PsiManager manager, 044 @NotNull FqName qualifiedName, 045 @NotNull GlobalSearchScope searchScope, 046 @NotNull Collection<JetFile> files // this is redundant, but computing it multiple times is costly 047 ) { 048 for (JetFile file : files) { 049 if (LightClassUtil.belongsToKotlinBuiltIns(file)) return null; 050 } 051 return new KotlinLightClassForPackage(manager, qualifiedName, searchScope, files); 052 } 053 054 private final FqName packageFqName; 055 private final FqName packageClassFqName; // derived from packageFqName 056 private final GlobalSearchScope searchScope; 057 private final Collection<JetFile> files; 058 private final int hashCode; 059 private final CachedValue<PsiJavaFileStub> javaFileStub; 060 061 private KotlinLightClassForPackage( 062 @NotNull PsiManager manager, 063 @NotNull FqName packageFqName, 064 @NotNull GlobalSearchScope searchScope, 065 @NotNull Collection<JetFile> files 066 ) { 067 super(manager); 068 this.packageFqName = packageFqName; 069 this.packageClassFqName = PackageClassUtils.getPackageClassFqName(packageFqName); 070 this.searchScope = searchScope; 071 assert !files.isEmpty() : "No files for package " + packageFqName; 072 this.files = Sets.newHashSet(files); // needed for hashCode 073 this.hashCode = computeHashCode(); 074 KotlinJavaFileStubProvider stubProvider = KotlinJavaFileStubProvider.createForPackageClass(getProject(), packageFqName, searchScope); 075 this.javaFileStub = CachedValuesManager.getManager(getProject()).createCachedValue(stubProvider, /*trackValue = */false); 076 } 077 078 @NotNull 079 @Override 080 public FqName getFqName() { 081 return packageClassFqName; 082 } 083 084 @Nullable 085 @Override 086 public String getName() { 087 return packageClassFqName.shortName().asString(); 088 } 089 090 @Nullable 091 @Override 092 public String getQualifiedName() { 093 return packageClassFqName.asString(); 094 } 095 096 @Override 097 public boolean isValid() { 098 return allValid(files); 099 } 100 101 private static boolean allValid(Collection<JetFile> files) { 102 for (JetFile file : files) { 103 if (!file.isValid()) return false; 104 } 105 return true; 106 } 107 108 @NotNull 109 @Override 110 public PsiElement copy() { 111 return new KotlinLightClassForPackage(getManager(), packageFqName, searchScope, files); 112 } 113 114 @NotNull 115 @Override 116 public PsiClass getDelegate() { 117 PsiClass psiClass = LightClassUtil.findClass(packageClassFqName, javaFileStub.getValue()); 118 if (psiClass == null) { 119 throw new IllegalStateException("Package class was not found " + packageFqName); 120 } 121 return psiClass; 122 } 123 124 @NotNull 125 @Override 126 public PsiElement getNavigationElement() { 127 return files.iterator().next(); 128 } 129 130 @Override 131 public boolean isEquivalentTo(PsiElement another) { 132 return another instanceof PsiClass && Comparing.equal(((PsiClass) another).getQualifiedName(), getQualifiedName()); 133 } 134 135 @Override 136 public ItemPresentation getPresentation() { 137 return ItemPresentationProviders.getItemPresentation(this); 138 } 139 140 @Override 141 public Icon getElementIcon(int flags) { 142 throw new UnsupportedOperationException("This should be done byt JetIconProvider"); 143 } 144 145 @Override 146 public int hashCode() { 147 return hashCode; 148 } 149 150 private int computeHashCode() { 151 int result = getManager().hashCode(); 152 result = 31 * result + files.hashCode(); 153 result = 31 * result + packageFqName.hashCode(); 154 return result; 155 } 156 157 @Override 158 public boolean equals(Object obj) { 159 if (this == obj) return true; 160 if (obj == null || getClass() != obj.getClass()) { 161 return false; 162 } 163 164 KotlinLightClassForPackage lightClass = (KotlinLightClassForPackage) obj; 165 166 if (this.hashCode != lightClass.hashCode) return false; 167 if (getManager() != lightClass.getManager()) return false; 168 if (!files.equals(lightClass.files)) return false; 169 if (!packageFqName.equals(lightClass.packageFqName)) return false; 170 171 return true; 172 } 173 174 @Override 175 public String toString() { 176 try { 177 return KotlinLightClassForPackage.class.getSimpleName() + ":" + getQualifiedName(); 178 } 179 catch (Throwable e) { 180 return KotlinLightClassForPackage.class.getSimpleName() + ":" + e.toString(); 181 } 182 } 183 184 }