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 017package org.jetbrains.jet.lang.resolve.lazy.descriptors; 018 019import com.google.common.base.Predicate; 020import com.google.common.base.Predicates; 021import com.google.common.collect.Collections2; 022import com.google.common.collect.Lists; 023import com.intellij.openapi.util.Computable; 024import com.intellij.psi.PsiElement; 025import com.intellij.util.Consumer; 026import org.jetbrains.annotations.NotNull; 027import org.jetbrains.annotations.Nullable; 028import org.jetbrains.jet.lang.descriptors.*; 029import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 030import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorBase; 031import org.jetbrains.jet.lang.psi.*; 032import org.jetbrains.jet.lang.resolve.AnnotationResolver; 033import org.jetbrains.jet.lang.resolve.BindingContext; 034import org.jetbrains.jet.lang.resolve.DescriptorResolver; 035import org.jetbrains.jet.lang.resolve.DescriptorUtils; 036import org.jetbrains.jet.lang.resolve.lazy.ForceResolveUtil; 037import org.jetbrains.jet.lang.resolve.lazy.LazyDescriptor; 038import org.jetbrains.jet.lang.resolve.lazy.ResolveSession; 039import org.jetbrains.jet.lang.resolve.lazy.ScopeProvider; 040import org.jetbrains.jet.lang.resolve.lazy.data.FilteringClassLikeInfo; 041import org.jetbrains.jet.lang.resolve.lazy.data.JetClassInfoUtil; 042import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo; 043import org.jetbrains.jet.lang.resolve.lazy.declarations.ClassMemberDeclarationProvider; 044import org.jetbrains.jet.lang.resolve.lazy.storage.NotNullLazyValue; 045import org.jetbrains.jet.lang.resolve.lazy.storage.NullableLazyValue; 046import org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager; 047import org.jetbrains.jet.lang.resolve.name.Name; 048import org.jetbrains.jet.lang.resolve.scopes.*; 049import org.jetbrains.jet.lang.types.ErrorUtils; 050import org.jetbrains.jet.lang.types.JetType; 051import org.jetbrains.jet.lang.types.TypeConstructor; 052import org.jetbrains.jet.lang.types.TypeUtils; 053 054import java.util.*; 055 056import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassObjectName; 057import static org.jetbrains.jet.lang.resolve.ModifiersChecker.*; 058 059public 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 private 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.resolveAnnotations(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}