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