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