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