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.lang.resolve.lazy.descriptors;
018
019 import com.google.common.base.Predicate;
020 import com.google.common.base.Predicates;
021 import com.google.common.collect.Collections2;
022 import com.google.common.collect.Lists;
023 import com.intellij.openapi.util.Computable;
024 import com.intellij.psi.PsiElement;
025 import com.intellij.util.Consumer;
026 import org.jetbrains.annotations.NotNull;
027 import org.jetbrains.annotations.Nullable;
028 import org.jetbrains.jet.lang.descriptors.*;
029 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
030 import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorBase;
031 import org.jetbrains.jet.lang.psi.*;
032 import org.jetbrains.jet.lang.resolve.AnnotationResolver;
033 import org.jetbrains.jet.lang.resolve.BindingContext;
034 import org.jetbrains.jet.lang.resolve.DescriptorResolver;
035 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
036 import org.jetbrains.jet.lang.resolve.lazy.ForceResolveUtil;
037 import org.jetbrains.jet.lang.resolve.lazy.LazyDescriptor;
038 import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
039 import org.jetbrains.jet.lang.resolve.lazy.ScopeProvider;
040 import org.jetbrains.jet.lang.resolve.lazy.data.FilteringClassLikeInfo;
041 import org.jetbrains.jet.lang.resolve.lazy.data.JetClassInfoUtil;
042 import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
043 import org.jetbrains.jet.lang.resolve.lazy.declarations.ClassMemberDeclarationProvider;
044 import org.jetbrains.jet.lang.resolve.lazy.storage.NotNullLazyValue;
045 import org.jetbrains.jet.lang.resolve.lazy.storage.NullableLazyValue;
046 import org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager;
047 import org.jetbrains.jet.lang.resolve.name.Name;
048 import org.jetbrains.jet.lang.resolve.scopes.*;
049 import org.jetbrains.jet.lang.types.ErrorUtils;
050 import org.jetbrains.jet.lang.types.JetType;
051 import org.jetbrains.jet.lang.types.TypeConstructor;
052 import org.jetbrains.jet.lang.types.TypeUtils;
053
054 import java.util.*;
055
056 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassObjectName;
057 import static org.jetbrains.jet.lang.resolve.ModifiersChecker.*;
058
059 public class LazyClassDescriptor extends ClassDescriptorBase implements LazyDescriptor, ClassDescriptor {
060
061 private static final Predicate<Object> ONLY_ENUM_ENTRIES = Predicates.instanceOf(JetEnumEntry.class);
062 private static final Predicate<JetType> VALID_SUPERTYPE = new Predicate<JetType>() {
063 @Override
064 public boolean apply(JetType type) {
065 assert !ErrorUtils.isErrorType(type) : "Error types must be filtered out in DescriptorResolver";
066 return TypeUtils.getClassDescriptor(type) != null;
067 }
068 };
069 private final ResolveSession resolveSession;
070 private final JetClassLikeInfo originalClassInfo;
071 private final ClassMemberDeclarationProvider declarationProvider;
072
073 private final Name name;
074 private final DeclarationDescriptor containingDeclaration;
075 private final LazyClassTypeConstructor typeConstructor;
076 private final Modality modality;
077 private final Visibility visibility;
078 private final ClassKind kind;
079 private final boolean isInner;
080
081 private final NotNullLazyValue<ReceiverParameterDescriptor> thisAsReceiverParameter;
082 private final NotNullLazyValue<List<AnnotationDescriptor>> annotations;
083 private final NullableLazyValue<ClassDescriptor> classObjectDescriptor;
084
085 private final LazyClassMemberScope unsubstitutedMemberScope;
086 private final JetScope unsubstitutedInnerClassesScope;
087
088 private final NotNullLazyValue<JetScope> scopeForClassHeaderResolution;
089 private final NotNullLazyValue<JetScope> scopeForMemberDeclarationResolution;
090 private final NotNullLazyValue<JetScope> scopeForPropertyInitializerResolution;
091
092 public LazyClassDescriptor(
093 @NotNull ResolveSession resolveSession,
094 @NotNull DeclarationDescriptor containingDeclaration,
095 @NotNull Name name,
096 @NotNull JetClassLikeInfo classLikeInfo
097 ) {
098 this.resolveSession = resolveSession;
099 this.name = name;
100
101 if (classLikeInfo.getCorrespondingClassOrObject() != null) {
102 this.resolveSession.getTrace().record(BindingContext.CLASS, classLikeInfo.getCorrespondingClassOrObject(), this);
103 }
104
105 this.originalClassInfo = classLikeInfo;
106 JetClassLikeInfo classLikeInfoForMembers =
107 classLikeInfo.getClassKind() != ClassKind.ENUM_CLASS ? classLikeInfo : noEnumEntries(classLikeInfo);
108 this.declarationProvider = resolveSession.getDeclarationProviderFactory().getClassMemberDeclarationProvider(classLikeInfoForMembers);
109 this.containingDeclaration = containingDeclaration;
110
111 this.unsubstitutedMemberScope = new LazyClassMemberScope(resolveSession, declarationProvider, this);
112 this.unsubstitutedInnerClassesScope = new InnerClassesScopeWrapper(unsubstitutedMemberScope);
113
114 this.typeConstructor = new LazyClassTypeConstructor();
115
116 JetModifierList modifierList = classLikeInfo.getModifierList();
117 this.kind = classLikeInfo.getClassKind();
118 if (kind.isObject()) {
119 this.modality = Modality.FINAL;
120 }
121 else {
122 Modality defaultModality = kind == ClassKind.TRAIT ? Modality.ABSTRACT : Modality.FINAL;
123 this.modality = resolveModalityFromModifiers(modifierList, defaultModality);
124 }
125 this.visibility = resolveVisibilityFromModifiers(modifierList, getDefaultClassVisibility(this));
126 this.isInner = isInnerClass(modifierList);
127
128 StorageManager storageManager = resolveSession.getStorageManager();
129 this.thisAsReceiverParameter = storageManager.createLazyValue(new Computable<ReceiverParameterDescriptor>() {
130 @Override
131 public ReceiverParameterDescriptor compute() {
132 return DescriptorResolver.createLazyReceiverParameterDescriptor(LazyClassDescriptor.this);
133 }
134 });
135 this.annotations = storageManager.createLazyValue(new Computable<List<AnnotationDescriptor>>() {
136 @Override
137 public List<AnnotationDescriptor> compute() {
138 return resolveAnnotations();
139 }
140 });
141 this.classObjectDescriptor = storageManager.createNullableLazyValue(new Computable<ClassDescriptor>() {
142 @Override
143 public ClassDescriptor compute() {
144 return computeClassObjectDescriptor();
145 }
146 });
147 this.scopeForClassHeaderResolution = storageManager.createLazyValue(new Computable<JetScope>() {
148 @Override
149 public JetScope compute() {
150 return computeScopeForClassHeaderResolution();
151 }
152 });
153 this.scopeForMemberDeclarationResolution = storageManager.createLazyValue(new Computable<JetScope>() {
154 @Override
155 public JetScope compute() {
156 return computeScopeForMemberDeclarationResolution();
157 }
158 });
159 this.scopeForPropertyInitializerResolution = storageManager.createLazyValue(new Computable<JetScope>() {
160 @Override
161 public JetScope compute() {
162 return computeScopeForPropertyInitializerResolution();
163 }
164 });
165 }
166
167 @Override
168 protected JetScope getScopeForMemberLookup() {
169 return unsubstitutedMemberScope;
170 }
171
172 @NotNull
173 @Override
174 public JetScope getUnsubstitutedInnerClassesScope() {
175 return unsubstitutedInnerClassesScope;
176 }
177
178 @NotNull
179 public JetScope getScopeForClassHeaderResolution() {
180 return scopeForClassHeaderResolution.compute();
181 }
182
183 @NotNull
184 private JetScope computeScopeForClassHeaderResolution() {
185 WritableScopeImpl scope = new WritableScopeImpl(JetScope.EMPTY, this, RedeclarationHandler.DO_NOTHING, "Scope with type parameters for " + name);
186 for (TypeParameterDescriptor typeParameterDescriptor : getTypeConstructor().getParameters()) {
187 scope.addClassifierDescriptor(typeParameterDescriptor);
188 }
189 scope.changeLockLevel(WritableScope.LockLevel.READING);
190
191 PsiElement scopeAnchor = declarationProvider.getOwnerInfo().getScopeAnchor();
192
193 return new ChainedScope(this, "ScopeForClassHeaderResolution: " + getName(),
194 scope,
195 getScopeProvider().getResolutionScopeForDeclaration(scopeAnchor));
196 }
197
198 @NotNull
199 public JetScope getScopeForMemberDeclarationResolution() {
200 return scopeForMemberDeclarationResolution.compute();
201 }
202
203 @NotNull
204 private JetScope computeScopeForMemberDeclarationResolution() {
205 WritableScopeImpl thisScope = new WritableScopeImpl(JetScope.EMPTY, this, RedeclarationHandler.DO_NOTHING, "Scope with 'this' for " + name);
206 thisScope.addLabeledDeclaration(this);
207 thisScope.changeLockLevel(WritableScope.LockLevel.READING);
208
209 ClassDescriptor classObject = getClassObjectDescriptor();
210 JetScope classObjectAdapterScope = (classObject != null) ? new ClassObjectMixinScope(classObject) : JetScope.EMPTY;
211
212 return new ChainedScope(
213 this,
214 "ScopeForMemberDeclarationResolution: " + getName(),
215 thisScope,
216 getScopeForMemberLookup(),
217 getScopeForClassHeaderResolution(),
218 classObjectAdapterScope);
219 }
220
221 @NotNull
222 public JetScope getScopeForPropertyInitializerResolution() {
223 return scopeForPropertyInitializerResolution.compute();
224 }
225
226 @NotNull
227 private JetScope computeScopeForPropertyInitializerResolution() {
228 ConstructorDescriptor primaryConstructor = getUnsubstitutedPrimaryConstructor();
229 if (primaryConstructor == null) return getScopeForMemberDeclarationResolution();
230
231 WritableScopeImpl scope = new WritableScopeImpl(JetScope.EMPTY, this, RedeclarationHandler.DO_NOTHING, "Scope with constructor parameters in " + name);
232 for (ValueParameterDescriptor valueParameterDescriptor : primaryConstructor.getValueParameters()) {
233 scope.addVariableDescriptor(valueParameterDescriptor);
234 }
235 scope.changeLockLevel(WritableScope.LockLevel.READING);
236
237 return new ChainedScope(
238 this,
239 "ScopeForPropertyInitializerResolution: " + getName(),
240 scope, getScopeForMemberDeclarationResolution());
241 }
242
243 @NotNull
244 @Override
245 public Collection<ConstructorDescriptor> getConstructors() {
246 return unsubstitutedMemberScope.getConstructors();
247 }
248
249 @Override
250 public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
251 return unsubstitutedMemberScope.getPrimaryConstructor();
252 }
253
254 @NotNull
255 @Override
256 public DeclarationDescriptor getOriginal() {
257 return this;
258 }
259
260 @NotNull
261 @Override
262 public DeclarationDescriptor getContainingDeclaration() {
263 return containingDeclaration;
264 }
265
266 @NotNull
267 @Override
268 public TypeConstructor getTypeConstructor() {
269 return typeConstructor;
270 }
271
272 @Override
273 public JetType getClassObjectType() {
274 ClassDescriptor classObjectDescriptor = getClassObjectDescriptor();
275 return classObjectDescriptor == null ? null : classObjectDescriptor.getDefaultType();
276 }
277
278 @Override
279 public ClassDescriptor getClassObjectDescriptor() {
280 return classObjectDescriptor.compute();
281 }
282
283 @Nullable
284 private ClassDescriptor computeClassObjectDescriptor() {
285 JetClassObject classObject = declarationProvider.getOwnerInfo().getClassObject();
286
287 JetClassLikeInfo classObjectInfo = getClassObjectInfo(classObject);
288 if (classObjectInfo != null) {
289 return new LazyClassDescriptor(resolveSession, this, getClassObjectName(getName()), classObjectInfo);
290 }
291 return null;
292 }
293
294 @Nullable
295 public JetClassLikeInfo getClassObjectInfo(JetClassObject classObject) {
296 if (classObject != null) {
297 if (!DescriptorUtils.inStaticContext(this)) {
298 return null;
299 }
300 JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration();
301 if (objectDeclaration != null) {
302 return JetClassInfoUtil.createClassLikeInfo(objectDeclaration);
303 }
304 }
305 else {
306 if (getKind() == ClassKind.ENUM_CLASS) {
307 // Enum classes always have class objects, and enum constants are their members
308 return enumClassObjectInfo(originalClassInfo);
309 }
310 }
311 return null;
312 }
313
314 @NotNull
315 @Override
316 public ClassKind getKind() {
317 return kind;
318 }
319
320 @NotNull
321 @Override
322 public Modality getModality() {
323 return modality;
324 }
325
326 @NotNull
327 @Override
328 public Visibility getVisibility() {
329 return visibility;
330 }
331
332 @Override
333 public boolean isInner() {
334 return isInner;
335 }
336
337 @NotNull
338 @Override
339 public ReceiverParameterDescriptor getThisAsReceiverParameter() {
340 return thisAsReceiverParameter.compute();
341 }
342
343 @Override
344 public List<AnnotationDescriptor> getAnnotations() {
345 return annotations.compute();
346 }
347
348 @NotNull
349 private List<AnnotationDescriptor> resolveAnnotations() {
350 JetClassLikeInfo classInfo = declarationProvider.getOwnerInfo();
351 JetModifierList modifierList = classInfo.getModifierList();
352 if (modifierList != null) {
353 AnnotationResolver annotationResolver = resolveSession.getInjector().getAnnotationResolver();
354 JetScope scopeForDeclaration = getScopeProvider().getResolutionScopeForDeclaration(classInfo.getScopeAnchor());
355 return annotationResolver.resolveAnnotationsWithArguments(scopeForDeclaration, modifierList, resolveSession.getTrace());
356 }
357 else {
358 return Collections.emptyList();
359 }
360 }
361
362 @NotNull
363 @Override
364 public Name getName() {
365 return name;
366 }
367
368 @Override
369 public String toString() {
370 return "lazy class " + getName().toString();
371 }
372
373 @Override
374 public void forceResolveAllContents() {
375 getAnnotations();
376 getClassObjectDescriptor();
377 getClassObjectType();
378 getConstructors();
379 getContainingDeclaration();
380 getThisAsReceiverParameter();
381 getKind();
382 getModality();
383 getName();
384 getOriginal();
385 getScopeForClassHeaderResolution();
386 getScopeForMemberDeclarationResolution();
387 ForceResolveUtil.forceResolveAllContents(getScopeForMemberLookup());
388 getScopeForPropertyInitializerResolution();
389 getUnsubstitutedInnerClassesScope();
390 ForceResolveUtil.forceResolveAllContents(getTypeConstructor());
391 getUnsubstitutedPrimaryConstructor();
392 getVisibility();
393 }
394
395 private class LazyClassTypeConstructor implements LazyDescriptor, TypeConstructor {
396 private final NotNullLazyValue<Collection<JetType>> supertypes = resolveSession.getStorageManager().createLazyValueWithPostCompute(
397 new Computable<Collection<JetType>>() {
398 @Override
399 public Collection<JetType> compute() {
400 if (resolveSession.isClassSpecial(DescriptorUtils.getFQName(LazyClassDescriptor.this))) {
401 return Collections.emptyList();
402 }
403 else {
404 JetClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
405 if (classOrObject == null) {
406 return Collections.emptyList();
407 }
408 else {
409 List<JetType> allSupertypes = resolveSession.getInjector().getDescriptorResolver()
410 .resolveSupertypes(getScopeForClassHeaderResolution(),
411 LazyClassDescriptor.this, classOrObject,
412 resolveSession.getTrace());
413
414 return Lists.newArrayList(Collections2.filter(allSupertypes, VALID_SUPERTYPE));
415 }
416 }
417 }
418 },
419 new Consumer<Collection<JetType>>() {
420 @Override
421 public void consume(@NotNull Collection<JetType> supertypes) {
422 findAndDisconnectLoopsInTypeHierarchy(supertypes);
423 }
424 });
425
426 private final NotNullLazyValue<List<TypeParameterDescriptor>> parameters = resolveSession.getStorageManager().createLazyValue(new Computable<List<TypeParameterDescriptor>>() {
427 @Override
428 public List<TypeParameterDescriptor> compute() {
429 JetClassLikeInfo classInfo = declarationProvider.getOwnerInfo();
430 List<JetTypeParameter> typeParameters = classInfo.getTypeParameters();
431
432 List<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>(typeParameters.size());
433 for (int i = 0; i < typeParameters.size(); i++) {
434 parameters.add(new LazyTypeParameterDescriptor(resolveSession, LazyClassDescriptor.this, typeParameters.get(i), i));
435 }
436
437 return parameters;
438 }
439 });
440
441 @NotNull
442 @Override
443 public List<TypeParameterDescriptor> getParameters() {
444 return parameters.compute();
445 }
446
447 @NotNull
448 @Override
449 public Collection<JetType> getSupertypes() {
450 return supertypes.compute();
451 }
452
453 private void findAndDisconnectLoopsInTypeHierarchy(Collection<JetType> supertypes) {
454 for (Iterator<JetType> iterator = supertypes.iterator(); iterator.hasNext(); ) {
455 JetType supertype = iterator.next();
456 if (isReachable(supertype.getConstructor(), this, new HashSet<TypeConstructor>())) {
457 iterator.remove();
458 }
459 }
460 }
461
462 private boolean isReachable(TypeConstructor from, TypeConstructor to, Set<TypeConstructor> visited) {
463 if (!visited.add(from)) return false;
464 for (JetType supertype : from.getSupertypes()) {
465 TypeConstructor supertypeConstructor = supertype.getConstructor();
466 if (supertypeConstructor == to) {
467 return true;
468 }
469 if (isReachable(supertypeConstructor, to, visited)) {
470 return true;
471 }
472 }
473 return false;
474 }
475
476 @Override
477 public boolean isSealed() {
478 return !getModality().isOverridable();
479 }
480
481 @Override
482 public ClassifierDescriptor getDeclarationDescriptor() {
483 return LazyClassDescriptor.this;
484 }
485
486 @Override
487 public List<AnnotationDescriptor> getAnnotations() {
488 return Collections.emptyList(); // TODO
489 }
490
491 @Override
492 public String toString() {
493 return LazyClassDescriptor.this.getName().toString();
494 }
495
496 @Override
497 public void forceResolveAllContents() {
498 getAnnotations();
499 getSupertypes();
500 getParameters();
501 }
502 }
503
504 private JetClassLikeInfo noEnumEntries(JetClassLikeInfo classLikeInfo) {
505 return new FilteringClassLikeInfo(resolveSession.getStorageManager(), classLikeInfo, Predicates.not(ONLY_ENUM_ENTRIES));
506 }
507
508 private JetClassLikeInfo enumClassObjectInfo(JetClassLikeInfo classLikeInfo) {
509 return new FilteringClassLikeInfo(resolveSession.getStorageManager(), classLikeInfo, ONLY_ENUM_ENTRIES) {
510 @Override
511 public JetClassOrObject getCorrespondingClassOrObject() {
512 return null;
513 }
514
515 @NotNull
516 @Override
517 public ClassKind getClassKind() {
518 return ClassKind.CLASS_OBJECT;
519 }
520
521 @NotNull
522 @Override
523 public List<? extends JetParameter> getPrimaryConstructorParameters() {
524 return Collections.emptyList();
525 }
526
527 @NotNull
528 @Override
529 public List<JetTypeParameter> getTypeParameters() {
530 return Collections.emptyList();
531 }
532 };
533 }
534
535 private ScopeProvider getScopeProvider() {
536 return resolveSession.getInjector().getScopeProvider();
537 }
538
539 }