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.collect.ImmutableSet; 020import com.google.common.collect.Lists; 021import com.intellij.openapi.util.Computable; 022import com.intellij.psi.PsiElement; 023import org.jetbrains.annotations.NotNull; 024import org.jetbrains.annotations.Nullable; 025import org.jetbrains.jet.lang.descriptors.*; 026import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl; 027import org.jetbrains.jet.lang.diagnostics.Errors; 028import org.jetbrains.jet.lang.psi.*; 029import org.jetbrains.jet.lang.resolve.*; 030import org.jetbrains.jet.lang.resolve.lazy.ResolveSession; 031import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo; 032import org.jetbrains.jet.lang.resolve.lazy.declarations.ClassMemberDeclarationProvider; 033import org.jetbrains.jet.lang.resolve.lazy.storage.NullableLazyValue; 034import org.jetbrains.jet.lang.resolve.name.Name; 035import org.jetbrains.jet.lang.resolve.scopes.JetScope; 036import org.jetbrains.jet.lang.types.DeferredType; 037import org.jetbrains.jet.lang.types.ErrorUtils; 038import org.jetbrains.jet.lang.types.JetType; 039import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 040import org.jetbrains.jet.util.lazy.RecursionIntolerantLazyValue; 041 042import java.util.*; 043 044public class LazyClassMemberScope extends AbstractLazyMemberScope<LazyClassDescriptor, ClassMemberDeclarationProvider> { 045 046 @NotNull 047 private static final Set<ClassKind> GENERATE_CONSTRUCTORS_FOR = 048 ImmutableSet.of(ClassKind.CLASS, ClassKind.ANNOTATION_CLASS, ClassKind.OBJECT, 049 ClassKind.ENUM_CLASS, ClassKind.ENUM_ENTRY, ClassKind.CLASS_OBJECT); 050 051 private interface MemberExtractor<T extends CallableMemberDescriptor> { 052 MemberExtractor<FunctionDescriptor> EXTRACT_FUNCTIONS = new MemberExtractor<FunctionDescriptor>() { 053 @NotNull 054 @Override 055 public Collection<FunctionDescriptor> extract(@NotNull JetType extractFrom, @NotNull Name name) { 056 return extractFrom.getMemberScope().getFunctions(name); 057 } 058 }; 059 060 MemberExtractor<PropertyDescriptor> EXTRACT_PROPERTIES = new MemberExtractor<PropertyDescriptor>() { 061 @NotNull 062 @Override 063 public Collection<PropertyDescriptor> extract(@NotNull JetType extractFrom, @NotNull Name name) { 064 //noinspection unchecked 065 return (Collection) extractFrom.getMemberScope().getProperties(name); 066 } 067 }; 068 069 @NotNull 070 Collection<T> extract(@NotNull JetType extractFrom, @NotNull Name name); 071 } 072 073 private final NullableLazyValue<ConstructorDescriptor> primaryConstructor; 074 075 public LazyClassMemberScope( 076 @NotNull ResolveSession resolveSession, 077 @NotNull ClassMemberDeclarationProvider declarationProvider, 078 @NotNull LazyClassDescriptor thisClass 079 ) { 080 super(resolveSession, declarationProvider, thisClass); 081 this.primaryConstructor = resolveSession.getStorageManager().createNullableLazyValue(new Computable<ConstructorDescriptor>() { 082 @Override 083 public ConstructorDescriptor compute() { 084 return resolvePrimaryConstructor(); 085 } 086 }); 087 } 088 089 @NotNull 090 @Override 091 protected JetScope getScopeForMemberDeclarationResolution(JetDeclaration declaration) { 092 if (declaration instanceof JetProperty) { 093 return thisDescriptor.getScopeForPropertyInitializerResolution(); 094 } 095 return thisDescriptor.getScopeForMemberDeclarationResolution(); 096 } 097 098 private <D extends CallableMemberDescriptor> void generateFakeOverrides( 099 @NotNull Name name, 100 @NotNull Collection<D> fromSupertypes, 101 @NotNull final Collection<D> result, 102 @NotNull final Class<? extends D> exactDescriptorClass 103 ) { 104 OverrideResolver.generateOverridesInFunctionGroup( 105 name, 106 fromSupertypes, 107 Lists.newArrayList(result), 108 thisDescriptor, 109 new OverrideResolver.DescriptorSink() { 110 @Override 111 public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) { 112 assert exactDescriptorClass.isInstance(fakeOverride) : "Wrong descriptor type in an override: " + 113 fakeOverride + 114 " while expecting " + 115 exactDescriptorClass.getSimpleName(); 116 //noinspection unchecked 117 result.add((D) fakeOverride); 118 } 119 120 @Override 121 public void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent) { 122 BindingTrace trace = resolveSession.getTrace(); 123 JetDeclaration declaration = (JetDeclaration) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), 124 fromCurrent); 125 assert declaration != null : "fromCurrent can not be a fake override"; 126 trace.report(Errors.CONFLICTING_OVERLOADS 127 .on(declaration, fromCurrent, fromCurrent.getContainingDeclaration().getName().asString())); 128 } 129 } 130 ); 131 OverrideResolver.resolveUnknownVisibilities(result, resolveSession.getTrace()); 132 } 133 134 @NotNull 135 @Override 136 public Set<FunctionDescriptor> getFunctions(@NotNull Name name) { 137 // TODO: this should be handled by lazy function descriptors 138 Set<FunctionDescriptor> functions = super.getFunctions(name); 139 for (FunctionDescriptor functionDescriptor : functions) { 140 if (functionDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue; 141 PsiElement element = 142 BindingContextUtils.callableDescriptorToDeclaration(resolveSession.getTrace().getBindingContext(), functionDescriptor); 143 OverrideResolver.resolveUnknownVisibilityForMember((JetDeclaration) element, functionDescriptor, resolveSession.getTrace()); 144 } 145 return functions; 146 } 147 148 @Override 149 protected void getNonDeclaredFunctions(@NotNull Name name, @NotNull Set<FunctionDescriptor> result) { 150 Collection<FunctionDescriptor> fromSupertypes = Lists.newArrayList(); 151 for (JetType supertype : thisDescriptor.getTypeConstructor().getSupertypes()) { 152 fromSupertypes.addAll(supertype.getMemberScope().getFunctions(name)); 153 } 154 generateDelegatingDescriptors(name, MemberExtractor.EXTRACT_FUNCTIONS, result); 155 generateEnumClassObjectMethods(result, name); 156 generateDataClassMethods(result, name); 157 generateFakeOverrides(name, fromSupertypes, result, FunctionDescriptor.class); 158 } 159 160 private void generateDataClassMethods(@NotNull Collection<FunctionDescriptor> result, @NotNull Name name) { 161 if (!KotlinBuiltIns.getInstance().isData(thisDescriptor)) return; 162 163 ConstructorDescriptor constructor = getPrimaryConstructor(); 164 if (constructor == null) return; 165 166 int parameterIndex = 0; 167 for (ValueParameterDescriptor parameter : constructor.getValueParameters()) { 168 if (ErrorUtils.isErrorType(parameter.getType())) continue; 169 Set<VariableDescriptor> properties = getProperties(parameter.getName()); 170 if (properties.isEmpty()) continue; 171 assert properties.size() == 1 : "A constructor parameter is resolved to more than one (" + properties.size() + ") property: " + parameter; 172 PropertyDescriptor property = (PropertyDescriptor) properties.iterator().next(); 173 if (property == null) continue; 174 ++parameterIndex; 175 176 if (name.equals(Name.identifier(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX + parameterIndex))) { 177 SimpleFunctionDescriptor functionDescriptor = 178 DescriptorResolver.createComponentFunctionDescriptor(parameterIndex, property, 179 parameter, thisDescriptor, resolveSession.getTrace()); 180 result.add(functionDescriptor); 181 break; 182 } 183 } 184 if (!constructor.getValueParameters().isEmpty() && name.equals(DescriptorResolver.COPY_METHOD_NAME)) { 185 SimpleFunctionDescriptor copyFunctionDescriptor = DescriptorResolver.createCopyFunctionDescriptor( 186 constructor.getValueParameters(), 187 thisDescriptor, resolveSession.getTrace()); 188 result.add(copyFunctionDescriptor); 189 } 190 } 191 192 private void generateEnumClassObjectMethods(@NotNull Collection<? super FunctionDescriptor> result, @NotNull Name name) { 193 if (!DescriptorUtils.isEnumClassObject(thisDescriptor)) return; 194 195 if (name.equals(DescriptorResolver.VALUES_METHOD_NAME)) { 196 SimpleFunctionDescriptor valuesMethod = DescriptorResolver 197 .createEnumClassObjectValuesMethod(thisDescriptor, resolveSession.getTrace()); 198 result.add(valuesMethod); 199 } 200 else if (name.equals(DescriptorResolver.VALUE_OF_METHOD_NAME)) { 201 SimpleFunctionDescriptor valueOfMethod = DescriptorResolver 202 .createEnumClassObjectValueOfMethod(thisDescriptor, resolveSession.getTrace()); 203 result.add(valueOfMethod); 204 } 205 } 206 207 @NotNull 208 @Override 209 public Set<VariableDescriptor> getProperties(@NotNull Name name) { 210 // TODO: this should be handled by lazy property descriptors 211 Set<VariableDescriptor> properties = super.getProperties(name); 212 for (VariableDescriptor variableDescriptor : properties) { 213 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor; 214 if (propertyDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue; 215 PsiElement element = 216 BindingContextUtils.callableDescriptorToDeclaration(resolveSession.getTrace().getBindingContext(), propertyDescriptor); 217 OverrideResolver.resolveUnknownVisibilityForMember((JetDeclaration) element, propertyDescriptor, resolveSession.getTrace()); 218 } 219 return properties; 220 } 221 222 @Override 223 @SuppressWarnings("unchecked") 224 protected void getNonDeclaredProperties(@NotNull Name name, @NotNull Set<VariableDescriptor> result) { 225 JetClassLikeInfo classInfo = declarationProvider.getOwnerInfo(); 226 227 // From primary constructor parameters 228 ConstructorDescriptor primaryConstructor = getPrimaryConstructor(); 229 if (primaryConstructor != null) { 230 List<ValueParameterDescriptor> valueParameterDescriptors = primaryConstructor.getValueParameters(); 231 List<? extends JetParameter> primaryConstructorParameters = classInfo.getPrimaryConstructorParameters(); 232 assert valueParameterDescriptors.size() == primaryConstructorParameters.size() : "From descriptor: " + valueParameterDescriptors.size() + " but from PSI: " + primaryConstructorParameters.size(); 233 for (ValueParameterDescriptor valueParameterDescriptor : valueParameterDescriptors) { 234 JetParameter parameter = primaryConstructorParameters.get(valueParameterDescriptor.getIndex()); 235 if (parameter.getValOrVarNode() != null && name.equals(parameter.getNameAsName())) { 236 PropertyDescriptor propertyDescriptor = 237 resolveSession.getInjector().getDescriptorResolver().resolvePrimaryConstructorParameterToAProperty( 238 thisDescriptor, 239 valueParameterDescriptor, 240 thisDescriptor.getScopeForClassHeaderResolution(), 241 parameter, resolveSession.getTrace() 242 ); 243 result.add(propertyDescriptor); 244 } 245 } 246 } 247 248 // Members from supertypes 249 Collection<PropertyDescriptor> fromSupertypes = Lists.newArrayList(); 250 for (JetType supertype : thisDescriptor.getTypeConstructor().getSupertypes()) { 251 fromSupertypes.addAll((Set) supertype.getMemberScope().getProperties(name)); 252 } 253 generateDelegatingDescriptors(name, MemberExtractor.EXTRACT_PROPERTIES, result); 254 generateFakeOverrides(name, fromSupertypes, (Set) result, PropertyDescriptor.class); 255 } 256 257 private <T extends CallableMemberDescriptor> void generateDelegatingDescriptors( 258 @NotNull Name name, 259 @NotNull MemberExtractor<T> extractor, 260 @NotNull Set<? super T> result 261 ) { 262 for (JetDelegationSpecifier delegationSpecifier : declarationProvider.getOwnerInfo().getDelegationSpecifiers()) { 263 if (delegationSpecifier instanceof JetDelegatorByExpressionSpecifier) { 264 JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier; 265 JetTypeReference typeReference = specifier.getTypeReference(); 266 if (typeReference != null) { 267 JetType supertype = resolveSession.getInjector().getTypeResolver().resolveType( 268 thisDescriptor.getScopeForClassHeaderResolution(), 269 typeReference, 270 resolveSession.getTrace(), 271 false); 272 Collection<T> descriptors = 273 DelegationResolver.generateDelegatedMembers(thisDescriptor, extractor.extract(supertype, name)); 274 result.addAll(descriptors); 275 } 276 } 277 } 278 } 279 280 @Override 281 protected void addExtraDescriptors(@NotNull Collection<DeclarationDescriptor> result) { 282 for (JetType supertype : thisDescriptor.getTypeConstructor().getSupertypes()) { 283 for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) { 284 if (descriptor instanceof FunctionDescriptor) { 285 result.addAll(getFunctions(descriptor.getName())); 286 } 287 else if (descriptor instanceof PropertyDescriptor) { 288 result.addAll(getProperties(descriptor.getName())); 289 } 290 // Nothing else is inherited 291 } 292 } 293 294 result.addAll(getFunctions(DescriptorResolver.VALUES_METHOD_NAME)); 295 result.addAll(getFunctions(DescriptorResolver.VALUE_OF_METHOD_NAME)); 296 297 addDataClassMethods(result); 298 } 299 300 private void addDataClassMethods(@NotNull Collection<DeclarationDescriptor> result) { 301 if (!KotlinBuiltIns.getInstance().isData(thisDescriptor)) return; 302 303 ConstructorDescriptor constructor = getPrimaryConstructor(); 304 if (constructor == null) return; 305 306 // Generate componentN functions until there's no such function for some n 307 int n = 1; 308 while (true) { 309 Name componentName = Name.identifier(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX + n); 310 Set<FunctionDescriptor> functions = getFunctions(componentName); 311 if (functions.isEmpty()) break; 312 313 result.addAll(functions); 314 315 n++; 316 } 317 result.addAll(getFunctions(Name.identifier("copy"))); 318 } 319 320 @Override 321 public NamespaceDescriptor getNamespace(@NotNull Name name) { 322 return null; 323 } 324 325 @NotNull 326 @Override 327 protected ReceiverParameterDescriptor getImplicitReceiver() { 328 return thisDescriptor.getThisAsReceiverParameter(); 329 } 330 331 @NotNull 332 public Set<ConstructorDescriptor> getConstructors() { 333 ConstructorDescriptor constructor = getPrimaryConstructor(); 334 return constructor == null ? Collections.<ConstructorDescriptor>emptySet() : Collections.singleton(constructor); 335 } 336 337 @Nullable 338 public ConstructorDescriptor getPrimaryConstructor() { 339 return primaryConstructor.compute(); 340 } 341 342 @Nullable 343 private ConstructorDescriptor resolvePrimaryConstructor() { 344 ConstructorDescriptor primaryConstructor = null; 345 if (GENERATE_CONSTRUCTORS_FOR.contains(thisDescriptor.getKind())) { 346 JetClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject(); 347 if (!thisDescriptor.getKind().isObject()) { 348 JetClass jetClass = (JetClass) classOrObject; 349 ConstructorDescriptorImpl constructor = resolveSession.getInjector().getDescriptorResolver() 350 .resolvePrimaryConstructorDescriptor(thisDescriptor.getScopeForClassHeaderResolution(), 351 thisDescriptor, 352 jetClass, 353 resolveSession.getTrace()); 354 primaryConstructor = constructor; 355 setDeferredReturnType(constructor); 356 } 357 else { 358 ConstructorDescriptorImpl constructor = 359 DescriptorResolver.createAndRecordPrimaryConstructorForObject(classOrObject, thisDescriptor, resolveSession.getTrace()); 360 setDeferredReturnType(constructor); 361 primaryConstructor = constructor; 362 } 363 } 364 return primaryConstructor; 365 } 366 367 private void setDeferredReturnType(@NotNull ConstructorDescriptorImpl descriptor) { 368 descriptor.setReturnType(DeferredType.create(resolveSession.getTrace(), new RecursionIntolerantLazyValue<JetType>() { 369 @Override 370 protected JetType compute() { 371 return thisDescriptor.getDefaultType(); 372 } 373 })); 374 } 375 376 @Override 377 public String toString() { 378 // Do not add details here, they may compromise the laziness during debugging 379 return "lazy scope for class " + thisDescriptor.getName(); 380 } 381}