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