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.openapi.util.Pair;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor; 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.MutablePackageFragmentDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.PackageLikeBuilder; 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.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.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
@@ -39,7 +44,7 @@ import org.jetbrains.jet.renderer.DescriptorRenderer;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.*; import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.diagnostics.Errors.REDECLARATION;
public class DeclarationResolver { public class DeclarationResolver {
@NotNull @NotNull
@@ -328,17 +333,16 @@ public class DeclarationResolver {
return declarations; return declarations;
} }
private void checkRedeclarationsInInnerClassNames(@NotNull TopDownAnalysisContext c) { public void checkRedeclarationsInInnerClassNames(@NotNull TopDownAnalysisContext c) {
for (ClassDescriptorWithResolutionScopes classDescriptor : c.getClasses().values()) { for (ClassDescriptorWithResolutionScopes classDescriptor : c.getClasses().values()) {
MutableClassDescriptor mutableClassDescriptor = (MutableClassDescriptor) classDescriptor;
if (classDescriptor.getKind() == ClassKind.CLASS_OBJECT) { if (classDescriptor.getKind() == ClassKind.CLASS_OBJECT) {
// Class objects should be considered during analysing redeclarations in classes // Class objects should be considered during analysing redeclarations in classes
continue; continue;
} }
Collection<DeclarationDescriptor> allDescriptors = mutableClassDescriptor.getScopeForMemberLookup().getOwnDeclaredDescriptors(); Collection<DeclarationDescriptor> allDescriptors = classDescriptor.getScopeForMemberLookup().getOwnDeclaredDescriptors();
MutableClassDescriptorLite classObj = mutableClassDescriptor.getClassObjectDescriptor(); ClassDescriptorWithResolutionScopes classObj = classDescriptor.getClassObjectDescriptor();
if (classObj != null) { if (classObj != null) {
Collection<DeclarationDescriptor> classObjDescriptors = classObj.getScopeForMemberLookup().getOwnDeclaredDescriptors(); Collection<DeclarationDescriptor> classObjDescriptors = classObj.getScopeForMemberLookup().getOwnDeclaredDescriptors();
if (!classObjDescriptors.isEmpty()) { 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; package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Predicates; 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.google.common.collect.Sets;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import kotlin.Function1; import kotlin.Function1;
@@ -138,6 +140,8 @@ public class TopDownAnalyzer {
trace trace
).getResolveSession(); ).getResolveSession();
final Multimap<FqName, JetElement> topLevelFqNames = HashMultimap.create();
// fill in the context // fill in the context
for (PsiElement declaration : declarations) { for (PsiElement declaration : declarations) {
declaration.accept( 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) { private void registerScope(@Nullable JetDeclaration declaration, @NotNull JetDeclaration anchorForScope) {
if (declaration == null) return; if (declaration == null) return;
c.registerDeclaringScope( c.registerDeclaringScope(
@@ -176,6 +189,8 @@ public class TopDownAnalyzer {
DescriptorResolver.resolvePackageHeader(packageDirective, moduleDescriptor, trace); DescriptorResolver.resolvePackageHeader(packageDirective, moduleDescriptor, trace);
registerDeclarations(file.getDeclarations()); registerDeclarations(file.getDeclarations());
topLevelFqNames.put(JetPsiUtil.getFQName(file), packageDirective);
} }
resolveAndCheckImports(file, resolveSession); resolveAndCheckImports(file, resolveSession);
} }
@@ -186,13 +201,13 @@ public class TopDownAnalyzer {
} }
private void visitClassOrObject(@NotNull JetClassOrObject classOrObject) { private void visitClassOrObject(@NotNull JetClassOrObject classOrObject) {
c.getClasses().put( ClassDescriptorWithResolutionScopes descriptor = ForceResolveUtil.forceResolveAllContents(
classOrObject, (ClassDescriptorWithResolutionScopes) resolveSession.getClassDescriptor(classOrObject)
ForceResolveUtil.forceResolveAllContents(
(ClassDescriptorWithResolutionScopes) resolveSession.getClassDescriptor(classOrObject)
)
); );
c.getClasses().put(classOrObject, descriptor);
registerDeclarations(classOrObject.getDeclarations()); registerDeclarations(classOrObject.getDeclarations());
registerTopLevelFqName(classOrObject, descriptor);
checkManyClassObjects(classOrObject); checkManyClassObjects(classOrObject);
} }
@@ -249,12 +264,13 @@ public class TopDownAnalyzer {
@Override @Override
public void visitProperty(@NotNull JetProperty property) { public void visitProperty(@NotNull JetProperty property) {
c.getProperties().put( PropertyDescriptor descriptor = ForceResolveUtil.forceResolveAllContents(
property, (PropertyDescriptor) resolveSession.resolveToDescriptor(property)
ForceResolveUtil.forceResolveAllContents(
(PropertyDescriptor) resolveSession.resolveToDescriptor(property)
)
); );
c.getProperties().put(property, descriptor);
registerTopLevelFqName(property, descriptor);
registerScope(property, property); registerScope(property, property);
registerScope(property.getGetter(), property); registerScope(property.getGetter(), property);
registerScope(property.getSetter(), property); registerScope(property.getSetter(), property);
@@ -262,6 +278,9 @@ public class TopDownAnalyzer {
} }
); );
} }
declarationResolver.checkRedeclarationsInPackages(resolveSession, topLevelFqNames);
declarationResolver.checkRedeclarationsInInnerClassNames(c);
overrideResolver.check(c); overrideResolver.check(c);
} }
else { else {
@@ -23,8 +23,11 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Function; import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.ContainerUtil;
import kotlin.Function0; import kotlin.Function0;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ReadOnly;
import org.jetbrains.jet.context.GlobalContextImpl; import org.jetbrains.jet.context.GlobalContextImpl;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
@@ -199,6 +202,24 @@ public class ResolveSession implements KotlinCodeAnalyzer {
return exceptionTracker; 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 @Override
@NotNull @NotNull
public ClassDescriptor getClassDescriptor(@NotNull JetClassOrObject classOrObject) { public ClassDescriptor getClassDescriptor(@NotNull JetClassOrObject classOrObject) {
@@ -451,4 +472,4 @@ public class ResolveSession implements KotlinCodeAnalyzer {
public QualifiedExpressionResolver getQualifiedExpressionResolver() { public QualifiedExpressionResolver getQualifiedExpressionResolver() {
return qualifiedExpressionResolver; return qualifiedExpressionResolver;
} }
} }
@@ -165,7 +165,7 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements LazyEnti
@NotNull @NotNull
@Override @Override
protected JetScope getScopeForMemberLookup() { public JetScope getScopeForMemberLookup() {
return unsubstitutedMemberScope; return unsubstitutedMemberScope;
} }
@@ -33,6 +33,9 @@ public interface ClassDescriptorWithResolutionScopes extends ClassDescriptor {
@NotNull @NotNull
JetScope getScopeForInitializerResolution(); JetScope getScopeForInitializerResolution();
@NotNull
JetScope getScopeForMemberLookup();
@Nullable @Nullable
@Override @Override
ClassDescriptorWithResolutionScopes getClassObjectDescriptor(); ClassDescriptorWithResolutionScopes getClassObjectDescriptor();