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