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;
018
019import com.google.common.base.Function;
020import com.google.common.base.Predicate;
021import com.google.common.collect.*;
022import com.intellij.openapi.util.Pair;
023import com.intellij.psi.PsiElement;
024import org.jetbrains.annotations.NotNull;
025import org.jetbrains.annotations.Nullable;
026import org.jetbrains.jet.lang.descriptors.*;
027import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
028import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptorLite;
029import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorImpl;
030import org.jetbrains.jet.lang.descriptors.impl.NamespaceLikeBuilder;
031import org.jetbrains.jet.lang.psi.*;
032import org.jetbrains.jet.lang.resolve.name.Name;
033import org.jetbrains.jet.lang.resolve.scopes.JetScope;
034import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
035import org.jetbrains.jet.lang.types.ErrorUtils;
036import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
037import org.jetbrains.jet.renderer.DescriptorRenderer;
038
039import javax.inject.Inject;
040import java.util.*;
041
042import static org.jetbrains.jet.lang.diagnostics.Errors.*;
043
044public class DeclarationResolver {
045    @NotNull
046    private AnnotationResolver annotationResolver;
047    @NotNull
048    private TopDownAnalysisContext context;
049    @NotNull
050    private ImportsResolver importsResolver;
051    @NotNull
052    private DescriptorResolver descriptorResolver;
053    @NotNull
054    private ScriptHeaderResolver scriptHeaderResolver;
055    @NotNull
056    private BindingTrace trace;
057
058
059    @Inject
060    public void setAnnotationResolver(@NotNull AnnotationResolver annotationResolver) {
061        this.annotationResolver = annotationResolver;
062    }
063
064    @Inject
065    public void setContext(@NotNull TopDownAnalysisContext context) {
066        this.context = context;
067    }
068
069    @Inject
070    public void setImportsResolver(@NotNull ImportsResolver importsResolver) {
071        this.importsResolver = importsResolver;
072    }
073
074    @Inject
075    public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
076        this.descriptorResolver = descriptorResolver;
077    }
078
079    @Inject
080    public void setTrace(@NotNull BindingTrace trace) {
081        this.trace = trace;
082    }
083
084    @Inject
085    public void setScriptHeaderResolver(@NotNull ScriptHeaderResolver scriptHeaderResolver) {
086        this.scriptHeaderResolver = scriptHeaderResolver;
087    }
088
089
090
091    public void process(@NotNull JetScope rootScope) {
092        resolveAnnotationConstructors();
093        resolveConstructorHeaders();
094        resolveAnnotationStubsOnClassesAndConstructors();
095        resolveFunctionAndPropertyHeaders();
096        createFunctionsForDataClasses();
097        importsResolver.processMembersImports(rootScope);
098        checkRedeclarationsInNamespaces();
099        checkRedeclarationsInInnerClassNames();
100    }
101
102    private void resolveAnnotationConstructors() {
103        for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
104            MutableClassDescriptor classDescriptor = entry.getValue();
105
106            if (DescriptorUtils.isAnnotationClass(classDescriptor)) {
107                processPrimaryConstructor(classDescriptor, entry.getKey());
108            }
109        }
110    }
111
112    private void resolveConstructorHeaders() {
113        for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
114            MutableClassDescriptor classDescriptor = entry.getValue();
115
116            if (!DescriptorUtils.isAnnotationClass(classDescriptor)) {
117                processPrimaryConstructor(classDescriptor, entry.getKey());
118            }
119        }
120    }
121
122    private void resolveAnnotationStubsOnClassesAndConstructors() {
123        for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
124            JetClass jetClass = entry.getKey();
125            MutableClassDescriptor descriptor = entry.getValue();
126            resolveAnnotationsForClassOrObject(annotationResolver, jetClass, descriptor);
127        }
128        for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
129            JetObjectDeclaration objectDeclaration = entry.getKey();
130            MutableClassDescriptor descriptor = entry.getValue();
131            resolveAnnotationsForClassOrObject(annotationResolver, objectDeclaration, descriptor);
132        }
133    }
134
135    private void resolveAnnotationsForClassOrObject(AnnotationResolver annotationResolver, JetClassOrObject jetClass, MutableClassDescriptor descriptor) {
136        JetModifierList modifierList = jetClass.getModifierList();
137        if (modifierList != null) {
138            descriptor.getAnnotations().addAll(annotationResolver.resolveAnnotations(descriptor.getScopeForSupertypeResolution(), modifierList, trace));
139        }
140    }
141
142    private void resolveFunctionAndPropertyHeaders() {
143        for (Map.Entry<JetFile, WritableScope> entry : context.getNamespaceScopes().entrySet()) {
144            JetFile namespace = entry.getKey();
145            WritableScope namespaceScope = entry.getValue();
146            NamespaceLikeBuilder namespaceDescriptor = context.getNamespaceDescriptors().get(namespace).getBuilder();
147
148            resolveFunctionAndPropertyHeaders(namespace.getDeclarations(), namespaceScope, namespaceScope, namespaceScope, namespaceDescriptor);
149        }
150        for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
151            JetClass jetClass = entry.getKey();
152            MutableClassDescriptor classDescriptor = entry.getValue();
153
154            JetClassBody jetClassBody = jetClass.getBody();
155            if (classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS && jetClassBody != null) {
156                trace.report(ANNOTATION_CLASS_WITH_BODY.on(jetClassBody));
157            }
158
159            resolveFunctionAndPropertyHeaders(
160                    jetClass.getDeclarations(), classDescriptor.getScopeForMemberResolution(),
161                    classDescriptor.getScopeForInitializers(), classDescriptor.getScopeForMemberResolution(),
162                    classDescriptor.getBuilder());
163            //            processPrimaryConstructor(classDescriptor, jetClass);
164            //            for (JetSecondaryConstructor jetConstructor : jetClass.getSecondaryConstructors()) {
165            //                processSecondaryConstructor(classDescriptor, jetConstructor);
166            //            }
167        }
168        for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
169            JetObjectDeclaration object = entry.getKey();
170            MutableClassDescriptor classDescriptor = entry.getValue();
171
172            resolveFunctionAndPropertyHeaders(object.getDeclarations(), classDescriptor.getScopeForMemberResolution(),
173                    classDescriptor.getScopeForInitializers(), classDescriptor.getScopeForMemberResolution(),
174                    classDescriptor.getBuilder());
175        }
176
177        scriptHeaderResolver.resolveScriptDeclarations();
178
179        // TODO : Extensions
180    }
181
182    private void resolveFunctionAndPropertyHeaders(@NotNull List<JetDeclaration> declarations,
183            final @NotNull JetScope scopeForFunctions,
184            final @NotNull JetScope scopeForPropertyInitializers, final @NotNull JetScope scopeForPropertyAccessors,
185            final @NotNull NamespaceLikeBuilder namespaceLike)
186    {
187        for (JetDeclaration declaration : declarations) {
188            declaration.accept(new JetVisitorVoid() {
189                @Override
190                public void visitNamedFunction(JetNamedFunction function) {
191                    SimpleFunctionDescriptor functionDescriptor = descriptorResolver.resolveFunctionDescriptor(namespaceLike.getOwnerForChildren(), scopeForFunctions, function, trace);
192                    namespaceLike.addFunctionDescriptor(functionDescriptor);
193                    context.getFunctions().put(function, functionDescriptor);
194                    context.registerDeclaringScope(function, scopeForFunctions);
195                }
196
197                @Override
198                public void visitProperty(JetProperty property) {
199                    PropertyDescriptor propertyDescriptor = descriptorResolver.resolvePropertyDescriptor(namespaceLike.getOwnerForChildren(), scopeForPropertyInitializers, property, trace);
200                    namespaceLike.addPropertyDescriptor(propertyDescriptor);
201                    context.getProperties().put(property, propertyDescriptor);
202                    context.registerDeclaringScope(property, scopeForPropertyInitializers);
203                    JetPropertyAccessor getter = property.getGetter();
204                    if (getter != null) {
205                        context.registerDeclaringScope(getter, scopeForPropertyAccessors);
206                    }
207                    JetPropertyAccessor setter = property.getSetter();
208                    if (setter != null) {
209                        context.registerDeclaringScope(setter, scopeForPropertyAccessors);
210                    }
211                }
212
213                @Override
214                public void visitObjectDeclaration(JetObjectDeclaration declaration) {
215                    PropertyDescriptor propertyDescriptor = descriptorResolver.resolveObjectDeclarationAsPropertyDescriptor(
216                            namespaceLike.getOwnerForChildren(), declaration, context.getObjects().get(declaration), trace);
217
218                    namespaceLike.addPropertyDescriptor(propertyDescriptor);
219                }
220
221                @Override
222                public void visitEnumEntry(JetEnumEntry enumEntry) {
223                    // FIX: Bad cast
224                    MutableClassDescriptorLite classObjectDescriptor =
225                            ((MutableClassDescriptorLite)namespaceLike.getOwnerForChildren()).getClassObjectDescriptor();
226                    assert classObjectDescriptor != null;
227                    PropertyDescriptor propertyDescriptor = descriptorResolver.resolveObjectDeclarationAsPropertyDescriptor(
228                            classObjectDescriptor, enumEntry, context.getClasses().get(enumEntry), trace);
229                    classObjectDescriptor.getBuilder().addPropertyDescriptor(propertyDescriptor);
230                }
231            });
232        }
233    }
234
235    private void createFunctionsForDataClasses() {
236        for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
237            JetClass jetClass = entry.getKey();
238            MutableClassDescriptor classDescriptor = entry.getValue();
239
240            if (jetClass.hasPrimaryConstructor() && KotlinBuiltIns.getInstance().isData(classDescriptor)) {
241                ConstructorDescriptor constructor = DescriptorUtils.getConstructorOfDataClass(classDescriptor);
242                createComponentFunctions(classDescriptor, constructor);
243                createCopyFunction(classDescriptor, constructor);
244            }
245        }
246    }
247
248    private void createComponentFunctions(@NotNull MutableClassDescriptor classDescriptor, @NotNull ConstructorDescriptor constructorDescriptor) {
249        int parameterIndex = 0;
250        for (ValueParameterDescriptor parameter : constructorDescriptor.getValueParameters()) {
251            if (!ErrorUtils.isErrorType(parameter.getType())) {
252                PropertyDescriptor property = trace.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter);
253                if (property != null) {
254                    ++parameterIndex;
255
256                    SimpleFunctionDescriptor functionDescriptor =
257                            DescriptorResolver.createComponentFunctionDescriptor(parameterIndex, property, parameter, classDescriptor, trace);
258
259                    classDescriptor.getBuilder().addFunctionDescriptor(functionDescriptor);
260                }
261            }
262        }
263    }
264
265    private void createCopyFunction(@NotNull MutableClassDescriptor classDescriptor, @NotNull ConstructorDescriptor constructorDescriptor) {
266        SimpleFunctionDescriptor functionDescriptor = DescriptorResolver.createCopyFunctionDescriptor(
267                constructorDescriptor.getValueParameters(), classDescriptor, trace);
268
269        classDescriptor.getBuilder().addFunctionDescriptor(functionDescriptor);
270    }
271
272    private void processPrimaryConstructor(MutableClassDescriptor classDescriptor, JetClass klass) {
273        if (classDescriptor.getKind() == ClassKind.TRAIT) {
274            JetParameterList primaryConstructorParameterList = klass.getPrimaryConstructorParameterList();
275            if (primaryConstructorParameterList != null) {
276                trace.report(CONSTRUCTOR_IN_TRAIT.on(primaryConstructorParameterList));
277            }
278        }
279
280        // TODO : not all the parameters are real properties
281        JetScope memberScope = classDescriptor.getScopeForSupertypeResolution();
282        ConstructorDescriptor constructorDescriptor = descriptorResolver.resolvePrimaryConstructorDescriptor(memberScope, classDescriptor, klass, trace);
283        if (constructorDescriptor != null) {
284            List<ValueParameterDescriptor> valueParameterDescriptors = constructorDescriptor.getValueParameters();
285            List<JetParameter> primaryConstructorParameters = klass.getPrimaryConstructorParameters();
286            assert valueParameterDescriptors.size() == primaryConstructorParameters.size();
287            for (ValueParameterDescriptor valueParameterDescriptor : valueParameterDescriptors) {
288                JetParameter parameter = primaryConstructorParameters.get(valueParameterDescriptor.getIndex());
289                if (parameter.getValOrVarNode() != null) {
290                    PropertyDescriptor propertyDescriptor = descriptorResolver.resolvePrimaryConstructorParameterToAProperty(
291                            classDescriptor,
292                            valueParameterDescriptor,
293                            memberScope,
294                            parameter, trace
295                    );
296                    classDescriptor.getBuilder().addPropertyDescriptor(propertyDescriptor);
297                    context.getPrimaryConstructorParameterProperties().put(parameter, propertyDescriptor);
298                }
299            }
300            if (classDescriptor.getKind() != ClassKind.TRAIT) {
301                classDescriptor.setPrimaryConstructor(constructorDescriptor, trace);
302            }
303        }
304    }
305
306    private void checkRedeclarationsInNamespaces() {
307        for (NamespaceDescriptorImpl descriptor : context.getNamespaceDescriptors().values()) {
308            Multimap<Name, DeclarationDescriptor> simpleNameDescriptors = descriptor.getMemberScope().getDeclaredDescriptorsAccessibleBySimpleName();
309            for (Name name : simpleNameDescriptors.keySet()) {
310                // Keep only properties with no receiver
311                Collection<DeclarationDescriptor> descriptors = Collections2.filter(simpleNameDescriptors.get(name), new Predicate<DeclarationDescriptor>() {
312                    @Override
313                    public boolean apply(@Nullable DeclarationDescriptor descriptor) {
314                        if (descriptor instanceof PropertyDescriptor) {
315                            PropertyDescriptor propertyDescriptor = (PropertyDescriptor)descriptor;
316                            return propertyDescriptor.getReceiverParameter() == null;
317                        }
318                        return true;
319                    }
320                });
321                if (descriptors.size() > 1) {
322                    for (DeclarationDescriptor declarationDescriptor : descriptors) {
323                        for (PsiElement declaration : getDeclarationsByDescriptor(declarationDescriptor)) {
324                            assert declaration != null : "Null declaration for descriptor: " + declarationDescriptor + " " +
325                                                         (declarationDescriptor != null ? DescriptorRenderer.TEXT.render(declarationDescriptor) : "");
326                            trace.report(REDECLARATION.on(declaration, declarationDescriptor.getName().asString()));
327                        }
328                    }
329                }
330            }
331        }
332    }
333
334    private Collection<PsiElement> getDeclarationsByDescriptor(DeclarationDescriptor declarationDescriptor) {
335        Collection<PsiElement> declarations;
336        if (declarationDescriptor instanceof NamespaceDescriptor) {
337            final NamespaceDescriptor namespace = (NamespaceDescriptor)declarationDescriptor;
338            Collection<JetFile> files = trace.get(BindingContext.NAMESPACE_TO_FILES, namespace);
339
340            if (files == null) {
341                throw new IllegalStateException("declarations corresponding to " + namespace + " are not found");
342            }
343
344            declarations = Collections2.transform(files, new Function<JetFile, PsiElement>() {
345                @Override
346                public PsiElement apply(@Nullable JetFile file) {
347                    assert file != null : "File is null for namespace " + namespace;
348                    return file.getNamespaceHeader().getNameIdentifier();
349                }
350            });
351        }
352        else {
353            declarations = Collections.singletonList(BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), declarationDescriptor));
354        }
355        return declarations;
356    }
357
358    private void checkRedeclarationsInInnerClassNames() {
359        Iterable<MutableClassDescriptor> classesAndObjects = Iterables.concat(context.getClasses().values(), context.getObjects().values());
360        for (MutableClassDescriptor classDescriptor : classesAndObjects) {
361            if (classDescriptor.getKind() == ClassKind.CLASS_OBJECT) {
362                // Class objects should be considered during analysing redeclarations in classes
363                continue;
364            }
365
366            Collection<DeclarationDescriptor> allDescriptors = classDescriptor.getScopeForMemberLookup().getOwnDeclaredDescriptors();
367
368            MutableClassDescriptorLite classObj = classDescriptor.getClassObjectDescriptor();
369            if (classObj != null) {
370                Collection<DeclarationDescriptor> classObjDescriptors = classObj.getScopeForMemberLookup().getOwnDeclaredDescriptors();
371                if (!classObjDescriptors.isEmpty()) {
372                    allDescriptors = Lists.newArrayList(allDescriptors);
373                    allDescriptors.addAll(classObjDescriptors);
374                }
375            }
376
377            Multimap<Name, DeclarationDescriptor> descriptorMap = HashMultimap.create();
378            for (DeclarationDescriptor desc : allDescriptors) {
379                if (desc instanceof ClassDescriptor || desc instanceof PropertyDescriptor) {
380                    descriptorMap.put(desc.getName(), desc);
381                }
382            }
383
384           reportRedeclarations(descriptorMap);
385        }
386    }
387
388    private void reportRedeclarations(@NotNull Multimap<Name, DeclarationDescriptor> descriptorMap) {
389        Set<Pair<PsiElement, Name>> redeclarations = Sets.newHashSet();
390        for (Name name : descriptorMap.keySet()) {
391            Collection<DeclarationDescriptor> descriptors = descriptorMap.get(name);
392            if (descriptors.size() > 1) {
393                // We mustn't compare PropertyDescriptor with PropertyDescriptor because we do this at OverloadResolver
394                for (DeclarationDescriptor descriptor : descriptors) {
395                    if (descriptor instanceof ClassDescriptor) {
396                        for (DeclarationDescriptor descriptor2 : descriptors) {
397                            if (descriptor == descriptor2) {
398                                continue;
399                            }
400
401                            redeclarations.add(Pair.create(
402                                    BindingContextUtils.classDescriptorToDeclaration(trace.getBindingContext(), (ClassDescriptor) descriptor),
403                                    descriptor.getName()));
404                            if (descriptor2 instanceof PropertyDescriptor) {
405                                redeclarations.add(Pair.create(
406                                        BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), descriptor2),
407                                        descriptor2.getName()));
408                            }
409                        }
410                    }
411                }
412            }
413        }
414        for (Pair<PsiElement, Name> redeclaration : redeclarations) {
415            trace.report(REDECLARATION.on(redeclaration.getFirst(), redeclaration.getSecond().asString()));
416        }
417    }
418
419
420}