Redeclaration check supported in LAZY mode

This commit is contained in:
Andrey Breslav
2014-02-27 14:14:05 +04:00
parent 674d990ba1
commit 1e0910f9c6
5 changed files with 113 additions and 18 deletions
@@ -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<DeclarationDescriptor> allDescriptors = mutableClassDescriptor.getScopeForMemberLookup().getOwnDeclaredDescriptors();
Collection<DeclarationDescriptor> allDescriptors = classDescriptor.getScopeForMemberLookup().getOwnDeclaredDescriptors();
MutableClassDescriptorLite classObj = mutableClassDescriptor.getClassObjectDescriptor();
ClassDescriptorWithResolutionScopes classObj = classDescriptor.getClassObjectDescriptor();
if (classObj != null) {
Collection<DeclarationDescriptor> classObjDescriptors = classObj.getScopeForMemberLookup().getOwnDeclaredDescriptors();
if (!classObjDescriptors.isEmpty()) {
@@ -389,5 +393,53 @@ public class DeclarationResolver {
}
}
public void checkRedeclarationsInPackages(@NotNull ResolveSession resolveSession, @NotNull Multimap<FqName, JetElement> topLevelFqNames) {
for (Map.Entry<FqName, Collection<JetElement>> entry : topLevelFqNames.asMap().entrySet()) {
FqName fqName = entry.getKey();
Collection<JetElement> declarationsOrPackageDirectives = entry.getValue();
if (fqName.isRoot()) continue;
Set<DeclarationDescriptor> 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<DeclarationDescriptor> getTopLevelDescriptorsByFqName(@NotNull ResolveSession resolveSession, @NotNull FqName fqName) {
FqName parentFqName = fqName.parent();
Set<DeclarationDescriptor> descriptors = new HashSet<DeclarationDescriptor>();
LazyPackageDescriptor parentFragment = resolveSession.getPackageFragment(parentFqName);
if (parentFragment != null) {
// Filter out extension properties
descriptors.addAll(
KotlinPackage.filter(
parentFragment.getMemberScope().getProperties(fqName.shortName()),
new Function1<VariableDescriptor, Boolean>() {
@Override
public Boolean invoke(VariableDescriptor descriptor) {
return descriptor.getReceiverParameter() == null;
}
}
)
);
}
ContainerUtil.addIfNotNull(descriptors, resolveSession.getPackageFragment(fqName));
descriptors.addAll(resolveSession.getTopLevelClassDescriptors(fqName));
return descriptors;
}
}
@@ -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<FqName, JetElement> 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 {
@@ -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<ClassDescriptor> 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<JetClassOrObject, ClassDescriptor>() {
@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;
}
}
}
@@ -165,7 +165,7 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements LazyEnti
@NotNull
@Override
protected JetScope getScopeForMemberLookup() {
public JetScope getScopeForMemberLookup() {
return unsubstitutedMemberScope;
}
@@ -33,6 +33,9 @@ public interface ClassDescriptorWithResolutionScopes extends ClassDescriptor {
@NotNull
JetScope getScopeForInitializerResolution();
@NotNull
JetScope getScopeForMemberLookup();
@Nullable
@Override
ClassDescriptorWithResolutionScopes getClassObjectDescriptor();