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