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