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