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