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