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 com.intellij.openapi.util.Computable;
022 import com.intellij.psi.PsiElement;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.jet.lang.descriptors.*;
026 import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl;
027 import org.jetbrains.jet.lang.diagnostics.Errors;
028 import org.jetbrains.jet.lang.psi.*;
029 import org.jetbrains.jet.lang.resolve.*;
030 import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
031 import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
032 import org.jetbrains.jet.lang.resolve.lazy.declarations.ClassMemberDeclarationProvider;
033 import org.jetbrains.jet.lang.resolve.lazy.storage.NullableLazyValue;
034 import org.jetbrains.jet.lang.resolve.name.Name;
035 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
036 import org.jetbrains.jet.lang.types.DeferredType;
037 import org.jetbrains.jet.lang.types.ErrorUtils;
038 import org.jetbrains.jet.lang.types.JetType;
039 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
040 import org.jetbrains.jet.util.lazy.RecursionIntolerantLazyValue;
041
042 import java.util.*;
043
044 public 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 }