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.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 }