diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java index 13ba4ab7e6e..596d5958ece 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java @@ -22,14 +22,19 @@ import com.google.common.collect.*; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; import com.intellij.util.containers.ContainerUtil; +import kotlin.Function1; +import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor; -import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptorLite; import org.jetbrains.jet.lang.descriptors.impl.MutablePackageFragmentDescriptor; import org.jetbrains.jet.lang.descriptors.impl.PackageLikeBuilder; +import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.lazy.ResolveSession; +import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyPackageDescriptor; +import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; @@ -39,7 +44,7 @@ import org.jetbrains.jet.renderer.DescriptorRenderer; import javax.inject.Inject; import java.util.*; -import static org.jetbrains.jet.lang.diagnostics.Errors.*; +import static org.jetbrains.jet.lang.diagnostics.Errors.REDECLARATION; public class DeclarationResolver { @NotNull @@ -328,17 +333,16 @@ public class DeclarationResolver { return declarations; } - private void checkRedeclarationsInInnerClassNames(@NotNull TopDownAnalysisContext c) { + public void checkRedeclarationsInInnerClassNames(@NotNull TopDownAnalysisContext c) { for (ClassDescriptorWithResolutionScopes classDescriptor : c.getClasses().values()) { - MutableClassDescriptor mutableClassDescriptor = (MutableClassDescriptor) classDescriptor; if (classDescriptor.getKind() == ClassKind.CLASS_OBJECT) { // Class objects should be considered during analysing redeclarations in classes continue; } - Collection allDescriptors = mutableClassDescriptor.getScopeForMemberLookup().getOwnDeclaredDescriptors(); + Collection allDescriptors = classDescriptor.getScopeForMemberLookup().getOwnDeclaredDescriptors(); - MutableClassDescriptorLite classObj = mutableClassDescriptor.getClassObjectDescriptor(); + ClassDescriptorWithResolutionScopes classObj = classDescriptor.getClassObjectDescriptor(); if (classObj != null) { Collection classObjDescriptors = classObj.getScopeForMemberLookup().getOwnDeclaredDescriptors(); if (!classObjDescriptors.isEmpty()) { @@ -389,5 +393,53 @@ public class DeclarationResolver { } } + public void checkRedeclarationsInPackages(@NotNull ResolveSession resolveSession, @NotNull Multimap topLevelFqNames) { + for (Map.Entry> entry : topLevelFqNames.asMap().entrySet()) { + FqName fqName = entry.getKey(); + Collection declarationsOrPackageDirectives = entry.getValue(); + + if (fqName.isRoot()) continue; + + Set descriptors = getTopLevelDescriptorsByFqName(resolveSession, fqName); + + if (descriptors.size() > 1) { + for (JetElement declarationOrPackageDirective : declarationsOrPackageDirectives) { + PsiElement reportAt = declarationOrPackageDirective instanceof JetNamedDeclaration + ? declarationOrPackageDirective + : ((JetPackageDirective) declarationOrPackageDirective).getNameIdentifier(); + trace.report(Errors.REDECLARATION.on(reportAt, fqName.shortName().asString())); + } + } + } + } + + @NotNull + private static Set getTopLevelDescriptorsByFqName(@NotNull ResolveSession resolveSession, @NotNull FqName fqName) { + FqName parentFqName = fqName.parent(); + + Set descriptors = new HashSet(); + + LazyPackageDescriptor parentFragment = resolveSession.getPackageFragment(parentFqName); + if (parentFragment != null) { + // Filter out extension properties + descriptors.addAll( + KotlinPackage.filter( + parentFragment.getMemberScope().getProperties(fqName.shortName()), + new Function1() { + @Override + public Boolean invoke(VariableDescriptor descriptor) { + return descriptor.getReceiverParameter() == null; + } + } + ) + ); + } + + ContainerUtil.addIfNotNull(descriptors, resolveSession.getPackageFragment(fqName)); + + descriptors.addAll(resolveSession.getTopLevelClassDescriptors(fqName)); + return descriptors; + } + } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index c55e6a320a2..bfb1f3b0883 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -17,6 +17,8 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.base.Predicates; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.intellij.psi.PsiElement; import kotlin.Function1; @@ -138,6 +140,8 @@ public class TopDownAnalyzer { trace ).getResolveSession(); + final Multimap topLevelFqNames = HashMultimap.create(); + // fill in the context for (PsiElement declaration : declarations) { declaration.accept( @@ -148,6 +152,15 @@ public class TopDownAnalyzer { } } + private void registerTopLevelFqName(@NotNull JetNamedDeclaration declaration, @NotNull DeclarationDescriptor descriptor) { + if (DescriptorUtils.isTopLevelDeclaration(descriptor)) { + FqName fqName = JetPsiUtil.getFQName(declaration); + if (fqName != null) { + topLevelFqNames.put(fqName, declaration); + } + } + } + private void registerScope(@Nullable JetDeclaration declaration, @NotNull JetDeclaration anchorForScope) { if (declaration == null) return; c.registerDeclaringScope( @@ -176,6 +189,8 @@ public class TopDownAnalyzer { DescriptorResolver.resolvePackageHeader(packageDirective, moduleDescriptor, trace); registerDeclarations(file.getDeclarations()); + + topLevelFqNames.put(JetPsiUtil.getFQName(file), packageDirective); } resolveAndCheckImports(file, resolveSession); } @@ -186,13 +201,13 @@ public class TopDownAnalyzer { } private void visitClassOrObject(@NotNull JetClassOrObject classOrObject) { - c.getClasses().put( - classOrObject, - ForceResolveUtil.forceResolveAllContents( - (ClassDescriptorWithResolutionScopes) resolveSession.getClassDescriptor(classOrObject) - ) + ClassDescriptorWithResolutionScopes descriptor = ForceResolveUtil.forceResolveAllContents( + (ClassDescriptorWithResolutionScopes) resolveSession.getClassDescriptor(classOrObject) ); + + c.getClasses().put(classOrObject, descriptor); registerDeclarations(classOrObject.getDeclarations()); + registerTopLevelFqName(classOrObject, descriptor); checkManyClassObjects(classOrObject); } @@ -249,12 +264,13 @@ public class TopDownAnalyzer { @Override public void visitProperty(@NotNull JetProperty property) { - c.getProperties().put( - property, - ForceResolveUtil.forceResolveAllContents( - (PropertyDescriptor) resolveSession.resolveToDescriptor(property) - ) + PropertyDescriptor descriptor = ForceResolveUtil.forceResolveAllContents( + (PropertyDescriptor) resolveSession.resolveToDescriptor(property) ); + + c.getProperties().put(property, descriptor); + registerTopLevelFqName(property, descriptor); + registerScope(property, property); registerScope(property.getGetter(), property); registerScope(property.getSetter(), property); @@ -262,6 +278,9 @@ public class TopDownAnalyzer { } ); } + + declarationResolver.checkRedeclarationsInPackages(resolveSession, topLevelFqNames); + declarationResolver.checkRedeclarationsInInnerClassNames(c); overrideResolver.check(c); } else { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSession.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSession.java index 426e05c0711..ca844c8b8b4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSession.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSession.java @@ -23,8 +23,11 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import kotlin.Function0; +import kotlin.Function1; +import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.ReadOnly; import org.jetbrains.jet.context.GlobalContextImpl; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; @@ -199,6 +202,24 @@ public class ResolveSession implements KotlinCodeAnalyzer { return exceptionTracker; } + @NotNull + @ReadOnly + public Collection getTopLevelClassDescriptors(@NotNull FqName fqName) { + if (fqName.isRoot()) return Collections.emptyList(); + + PackageMemberDeclarationProvider provider = declarationProviderFactory.getPackageMemberDeclarationProvider(fqName.parent()); + if (provider == null) return Collections.emptyList(); + + return KotlinPackage.map( + provider.getClassOrObjectDeclarations(fqName.shortName()), + new Function1() { + @Override + public ClassDescriptor invoke(JetClassOrObject classOrObject) { + return getClassDescriptor(classOrObject); + } + }); + } + @Override @NotNull public ClassDescriptor getClassDescriptor(@NotNull JetClassOrObject classOrObject) { @@ -451,4 +472,4 @@ public class ResolveSession implements KotlinCodeAnalyzer { public QualifiedExpressionResolver getQualifiedExpressionResolver() { return qualifiedExpressionResolver; } -} \ No newline at end of file +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java index af108c803ce..4728ca3ae87 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java @@ -165,7 +165,7 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements LazyEnti @NotNull @Override - protected JetScope getScopeForMemberLookup() { + public JetScope getScopeForMemberLookup() { return unsubstitutedMemberScope; } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorWithResolutionScopes.java b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorWithResolutionScopes.java index a89d159bb6e..ad0efd0451e 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorWithResolutionScopes.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/ClassDescriptorWithResolutionScopes.java @@ -33,6 +33,9 @@ public interface ClassDescriptorWithResolutionScopes extends ClassDescriptor { @NotNull JetScope getScopeForInitializerResolution(); + @NotNull + JetScope getScopeForMemberLookup(); + @Nullable @Override ClassDescriptorWithResolutionScopes getClassObjectDescriptor();