Refactor: Extract ImportDirectiveProcessor from QualifiedExpressionResolver

J2K code
This commit is contained in:
Pavel V. Talanov
2015-05-13 15:08:03 +03:00
parent 8b9ddea729
commit 806098f8a0
3 changed files with 159 additions and 124 deletions
@@ -33,7 +33,7 @@ class AllUnderImportsScope : JetScope {
if (descriptor is PackageViewDescriptor) {
scopes.add(NoSubpackagesInPackageScope(descriptor))
}
else if (descriptor is ClassDescriptor && QualifiedExpressionResolver.canAllUnderImportFromClass(descriptor)) {
else if (descriptor is ClassDescriptor && ImportDirectiveProcessor.canAllUnderImportFromClass(descriptor)) {
scopes.add(descriptor.getStaticScope())
scopes.add(descriptor.getUnsubstitutedInnerClassesScope())
}
@@ -0,0 +1,136 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.JetImportDirective
import org.jetbrains.kotlin.psi.JetPsiUtil
import org.jetbrains.kotlin.psi.JetQualifiedExpression
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.resolve.scopes.JetScope
import kotlin.platform.platformStatic
public class ImportDirectiveProcessor(
private val qualifiedExpressionResolver: QualifiedExpressionResolver
) {
public fun processImportReference(
importDirective: JetImportDirective,
scope: JetScope,
scopeToCheckVisibility: JetScope,
trace: BindingTrace,
lookupMode: QualifiedExpressionResolver.LookupMode
): JetScope {
if (importDirective.isAbsoluteInRootPackage()) {
trace.report(Errors.UNSUPPORTED.on(importDirective, "TypeHierarchyResolver")) // TODO
return JetScope.Empty
}
val importedReference = importDirective.getImportedReference() ?: return JetScope.Empty
val descriptors: Collection<DeclarationDescriptor>
if (importedReference is JetQualifiedExpression) {
//store result only when we find all descriptors, not only classes on the second phase
descriptors = qualifiedExpressionResolver.lookupDescriptorsForQualifiedExpression(
importedReference, scope, scopeToCheckVisibility, trace, lookupMode, lookupMode == QualifiedExpressionResolver.LookupMode.EVERYTHING
)
}
else {
assert(importedReference is JetSimpleNameExpression)
descriptors = qualifiedExpressionResolver.lookupDescriptorsForSimpleNameReference(
importedReference as JetSimpleNameExpression, scope, scopeToCheckVisibility, trace, lookupMode, true, lookupMode == QualifiedExpressionResolver.LookupMode.EVERYTHING
)
}
val referenceExpression = JetPsiUtil.getLastReference(importedReference)
if (importDirective.isAllUnder()) {
if (!canAllUnderImportFrom(descriptors) && referenceExpression != null) {
val toReportOn = descriptors.filterIsInstance<ClassDescriptor>().iterator().next()
trace.report(Errors.CANNOT_IMPORT_ON_DEMAND_FROM_SINGLETON.on(referenceExpression, toReportOn))
}
if (referenceExpression == null || !canImportMembersFrom(descriptors, referenceExpression, trace, lookupMode)) {
return JetScope.Empty
}
val importsScope = AllUnderImportsScope()
for (descriptor in descriptors) {
importsScope.addAllUnderImport(descriptor)
}
return importsScope
}
else {
val aliasName = JetPsiUtil.getAliasName(importDirective)
if (aliasName == null) return JetScope.Empty
return SingleImportScope(aliasName, descriptors)
}
}
public companion object {
public fun canAllUnderImportFrom(descriptors: Collection<DeclarationDescriptor>): Boolean {
if (descriptors.isEmpty()) {
return true
}
for (descriptor in descriptors) {
if (descriptor !is ClassDescriptor) {
return true
}
if (canAllUnderImportFromClass(descriptor)) {
return true
}
}
return false
}
public fun canAllUnderImportFromClass(descriptor: ClassDescriptor): Boolean {
return !descriptor.getKind().isSingleton()
}
platformStatic public fun canImportMembersFrom(descriptors: Collection<DeclarationDescriptor>, reference: JetSimpleNameExpression, trace: BindingTrace, lookupMode: QualifiedExpressionResolver.LookupMode): Boolean {
if (lookupMode == QualifiedExpressionResolver.LookupMode.ONLY_CLASSES_AND_PACKAGES) {
return true
}
if (descriptors.size() == 1) {
return canImportMembersFrom(descriptors.iterator().next(), reference, trace, lookupMode)
}
val temporaryTrace = TemporaryBindingTrace.create(trace, "trace to find out if members can be imported from", reference)
var canImport = false
for (descriptor in descriptors) {
canImport = canImport or canImportMembersFrom(descriptor, reference, temporaryTrace, lookupMode)
}
if (!canImport) {
temporaryTrace.commit()
}
return canImport
}
private fun canImportMembersFrom(descriptor: DeclarationDescriptor, reference: JetSimpleNameExpression, trace: BindingTrace, lookupMode: QualifiedExpressionResolver.LookupMode): Boolean {
assert(lookupMode == QualifiedExpressionResolver.LookupMode.EVERYTHING)
if (descriptor is PackageViewDescriptor) {
return true
}
if (descriptor is ClassDescriptor) {
return true
}
trace.report(Errors.CANNOT_IMPORT_FROM_ELEMENT.on(reference, descriptor))
return false
}
}
}
@@ -21,7 +21,6 @@ import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.psi.util.PsiTreeUtil;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.Mutable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -43,6 +42,7 @@ import static org.jetbrains.kotlin.diagnostics.Errors.*;
public class QualifiedExpressionResolver {
private SymbolUsageValidator symbolUsageValidator;
private final ImportDirectiveProcessor importDirectiveProcessor = new ImportDirectiveProcessor(this);
/**
* @deprecated Instance of this class should be obtained from the Injector
@@ -71,25 +71,6 @@ public class QualifiedExpressionResolver {
EVERYTHING
}
public static boolean canAllUnderImportFrom(@NotNull Collection<DeclarationDescriptor> descriptors) {
if (descriptors.isEmpty()) {
return true;
}
for (DeclarationDescriptor descriptor : descriptors) {
if (!(descriptor instanceof ClassDescriptor)) {
return true;
}
if (canAllUnderImportFromClass((ClassDescriptor) descriptor)) {
return true;
}
}
return false;
}
public static boolean canAllUnderImportFromClass(@NotNull ClassDescriptor descriptor) {
return !descriptor.getKind().isSingleton();
}
@NotNull
public JetScope processImportReference(
@NotNull JetImportDirective importDirective,
@@ -98,94 +79,7 @@ public class QualifiedExpressionResolver {
@NotNull BindingTrace trace,
@NotNull LookupMode lookupMode
) {
if (importDirective.isAbsoluteInRootPackage()) {
trace.report(UNSUPPORTED.on(importDirective, "TypeHierarchyResolver")); // TODO
return JetScope.Empty.INSTANCE$;
}
JetExpression importedReference = importDirective.getImportedReference();
if (importedReference == null) {
return JetScope.Empty.INSTANCE$;
}
Collection<DeclarationDescriptor> descriptors;
if (importedReference instanceof JetQualifiedExpression) {
//store result only when we find all descriptors, not only classes on the second phase
descriptors = lookupDescriptorsForQualifiedExpression(
(JetQualifiedExpression) importedReference, scope, scopeToCheckVisibility, trace,
lookupMode, lookupMode == LookupMode.EVERYTHING);
}
else {
assert importedReference instanceof JetSimpleNameExpression;
descriptors = lookupDescriptorsForSimpleNameReference(
(JetSimpleNameExpression) importedReference, scope, scopeToCheckVisibility, trace,
lookupMode, true, lookupMode == LookupMode.EVERYTHING);
}
JetSimpleNameExpression referenceExpression = JetPsiUtil.getLastReference(importedReference);
if (importDirective.isAllUnder()) {
if (!canAllUnderImportFrom(descriptors) && referenceExpression != null) {
ClassDescriptor toReportOn = KotlinPackage.filterIsInstance(descriptors, ClassDescriptor.class).iterator().next();
trace.report(CANNOT_IMPORT_ON_DEMAND_FROM_SINGLETON.on(referenceExpression, toReportOn));
}
if (referenceExpression == null || !canImportMembersFrom(descriptors, referenceExpression, trace, lookupMode)) {
return JetScope.Empty.INSTANCE$;
}
AllUnderImportsScope importsScope = new AllUnderImportsScope();
for (DeclarationDescriptor descriptor : descriptors) {
importsScope.addAllUnderImport(descriptor);
}
return importsScope;
}
else {
Name aliasName = JetPsiUtil.getAliasName(importDirective);
if (aliasName == null) return JetScope.Empty.INSTANCE$;
return new SingleImportScope(aliasName, descriptors);
}
}
private static boolean canImportMembersFrom(
@NotNull Collection<DeclarationDescriptor> descriptors,
@NotNull JetSimpleNameExpression reference,
@NotNull BindingTrace trace,
@NotNull LookupMode lookupMode
) {
if (lookupMode == LookupMode.ONLY_CLASSES_AND_PACKAGES) {
return true;
}
if (descriptors.size() == 1) {
return canImportMembersFrom(descriptors.iterator().next(), reference, trace, lookupMode);
}
TemporaryBindingTrace temporaryTrace =
TemporaryBindingTrace.create(trace, "trace to find out if members can be imported from", reference);
boolean canImport = false;
for (DeclarationDescriptor descriptor : descriptors) {
canImport |= canImportMembersFrom(descriptor, reference, temporaryTrace, lookupMode);
}
if (!canImport) {
temporaryTrace.commit();
}
return canImport;
}
private static boolean canImportMembersFrom(
@NotNull DeclarationDescriptor descriptor,
@NotNull JetSimpleNameExpression reference,
@NotNull BindingTrace trace,
@NotNull LookupMode lookupMode
) {
assert lookupMode == LookupMode.EVERYTHING;
if (descriptor instanceof PackageViewDescriptor) {
return true;
}
if (descriptor instanceof ClassDescriptor) {
return true;
}
trace.report(CANNOT_IMPORT_FROM_ELEMENT.on(reference, descriptor));
return false;
return importDirectiveProcessor.processImportReference(importDirective, scope, scopeToCheckVisibility, trace, lookupMode);
}
@NotNull
@@ -211,27 +105,29 @@ public class QualifiedExpressionResolver {
JetScope filteredScope = filterOutPackagesIfNeeded(outerScope, onlyClassifiers);
if (qualifier == null) {
return lookupDescriptorsForSimpleNameReference(referenceExpression, filteredScope, outerScope, trace, LookupMode.ONLY_CLASSES_AND_PACKAGES,
return lookupDescriptorsForSimpleNameReference(referenceExpression, filteredScope, outerScope, trace,
LookupMode.ONLY_CLASSES_AND_PACKAGES,
false, true);
}
Collection<DeclarationDescriptor> declarationDescriptors = lookupDescriptorsForUserType(qualifier, outerScope, trace, false);
return lookupSelectorDescriptors(referenceExpression, declarationDescriptors, trace, filteredScope, LookupMode.ONLY_CLASSES_AND_PACKAGES, true);
return lookupSelectorDescriptors(referenceExpression, declarationDescriptors, trace, filteredScope,
LookupMode.ONLY_CLASSES_AND_PACKAGES, true);
}
private static JetScope filterOutPackagesIfNeeded(final JetScope outerScope, boolean noPackages) {
return !noPackages ? outerScope : new AbstractScopeAdapter() {
@NotNull
@Override
protected JetScope getWorkerScope() {
return outerScope;
}
@NotNull
@Override
protected JetScope getWorkerScope() {
return outerScope;
}
@Nullable
@Override
public PackageViewDescriptor getPackage(@NotNull Name name) {
return null;
}
@Nullable
@Override
public PackageViewDescriptor getPackage(@NotNull Name name) {
return null;
}
};
}
@@ -265,7 +161,8 @@ public class QualifiedExpressionResolver {
JetSimpleNameExpression selector = (JetSimpleNameExpression) selectorExpression;
JetSimpleNameExpression lastReference = JetPsiUtil.getLastReference(receiverExpression);
if (lastReference == null || !canImportMembersFrom(declarationDescriptors, lastReference, trace, lookupMode)) {
if (lastReference == null || !ImportDirectiveProcessor.canImportMembersFrom(declarationDescriptors, lastReference, trace,
lookupMode)) {
return Collections.emptyList();
}
@@ -454,7 +351,7 @@ public class QualifiedExpressionResolver {
if (descriptor instanceof ClassifierDescriptor) {
symbolUsageValidator.validateTypeUsage((ClassifierDescriptor) descriptor, trace, referenceExpression);
}
if (descriptor instanceof DeclarationDescriptorWithVisibility) {
checkVisibility((DeclarationDescriptorWithVisibility) descriptor, trace, referenceExpression, scopeToCheckVisibility);
}
@@ -518,7 +415,9 @@ public class QualifiedExpressionResolver {
) {
if (!Visibilities.isVisible(ReceiverValue.IRRELEVANT_RECEIVER, descriptor, scopeToCheckVisibility.getContainingDeclaration())) {
Visibility visibility = descriptor.getVisibility();
if (PsiTreeUtil.getParentOfType(referenceExpression, JetImportDirective.class) != null && !visibility.mustCheckInImports()) return;
if (PsiTreeUtil.getParentOfType(referenceExpression, JetImportDirective.class) != null && !visibility.mustCheckInImports()) {
return;
}
//noinspection ConstantConditions
trace.report(INVISIBLE_REFERENCE.on(referenceExpression, descriptor, visibility, descriptor.getContainingDeclaration()));
}