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