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 }