Avoid creating fake PSI for default imports

#KT-13860 Fixed
This commit is contained in:
Denis Zharkov
2018-07-09 15:05:15 +03:00
parent acf0bb349c
commit ec23695f77
8 changed files with 200 additions and 106 deletions
@@ -21,6 +21,8 @@ import com.intellij.util.SmartList
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
@@ -33,7 +35,10 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.ImportingScope
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.resolve.scopes.utils.*
import org.jetbrains.kotlin.resolve.scopes.utils.canBeResolvedWithoutDeprecation
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import org.jetbrains.kotlin.resolve.scopes.utils.findFirstClassifierWithDeprecationStatus
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext
import org.jetbrains.kotlin.types.expressions.isWithoutValueArguments
@@ -54,7 +59,7 @@ class QualifiedExpressionResolver {
}
data class TypeQualifierResolutionResult(
val qualifierParts: List<QualifierPart>,
val qualifierParts: List<ExpressionQualifierPart>,
val classifierDescriptor: ClassifierDescriptor? = null
) {
val allProjections: List<KtTypeProjection>
@@ -64,12 +69,12 @@ class QualifiedExpressionResolver {
fun LexicalScope.findClassifierAndReportDeprecationIfNeeded(
name: Name,
lookupLocation: KotlinLookupLocation,
reportOn: KtExpression,
reportOn: KtExpression?,
trace: BindingTrace
): ClassifierDescriptor? {
val (classifier, isDeprecated) = findFirstClassifierWithDeprecationStatus(name, lookupLocation) ?: return null
if (isDeprecated) {
if (isDeprecated && reportOn != null) {
trace.record(BindingContext.DEPRECATED_SHORT_NAME_ACCESS, reportOn) // For IDE
// slow-path: we know that closest classifier is imported by the deprecated path, but before reporting
@@ -118,7 +123,7 @@ class QualifiedExpressionResolver {
}
private fun resolveQualifierPartListForType(
qualifierPartList: List<QualifierPart>,
qualifierPartList: List<ExpressionQualifierPart>,
ownerDescriptor: DeclarationDescriptor?,
scope: LexicalScope,
trace: BindingTrace,
@@ -146,7 +151,8 @@ class QualifiedExpressionResolver {
return TypeQualifierResolutionResult(qualifierPartList, classifier)
}
private fun checkNotEnumEntry(descriptor: DeclarationDescriptor?, trace: BindingTrace, expression: KtSimpleNameExpression) {
private fun checkNotEnumEntry(descriptor: DeclarationDescriptor?, trace: BindingTrace, expression: KtSimpleNameExpression?) {
expression ?: return
if (descriptor != null && DescriptorUtils.isEnumEntry(descriptor)) {
val qualifiedParent = expression.getTopmostParentQualifiedExpressionForSelector()
if (qualifiedParent == null || qualifiedParent.parent !is KtDoubleColonExpression) {
@@ -183,14 +189,20 @@ class QualifiedExpressionResolver {
return resolveQualifierPartListForType(qualifierPartList, ownerDescriptor, scope, trace, isQualifier = true)
}
private fun KtUserType.asQualifierPartList(): Pair<List<QualifierPart>, Boolean> {
private fun KtUserType.asQualifierPartList(): Pair<List<ExpressionQualifierPart>, Boolean> {
var hasError = false
val result = SmartList<QualifierPart>()
val result = SmartList<ExpressionQualifierPart>()
var userType: KtUserType? = this
while (userType != null) {
val referenceExpression = userType.referenceExpression
if (referenceExpression != null) {
result.add(QualifierPart(referenceExpression.getReferencedNameAsName(), referenceExpression, userType.typeArgumentList))
result.add(
ExpressionQualifierPart(
referenceExpression.getReferencedNameAsName(),
referenceExpression,
userType.typeArgumentList
)
)
} else {
hasError = true
}
@@ -200,26 +212,20 @@ class QualifiedExpressionResolver {
}
fun processImportReference(
importDirective: KtImportDirective,
importDirective: KtImportInfo,
moduleDescriptor: ModuleDescriptor,
trace: BindingTrace,
excludedImportNames: Collection<FqName>,
packageFragmentForVisibilityCheck: PackageFragmentDescriptor?
): ImportingScope? { // null if some error happened
val importedReference = importDirective.importedReference ?: return null
val importedReference = importDirective.importContent ?: return null
val path = importedReference.asQualifierPartList()
val lastPart = path.lastOrNull() ?: return null
val packageFragmentForCheck =
when {
importDirective.suppressDiagnosticsInDebugMode() -> null
packageFragmentForVisibilityCheck is DeclarationDescriptorWithSource && packageFragmentForVisibilityCheck.source == SourceElement.NO_SOURCE -> {
PackageFragmentWithCustomSource(
packageFragmentForVisibilityCheck,
KotlinSourceElement(importDirective.containingKtFile)
)
}
else -> packageFragmentForVisibilityCheck
}
if (importDirective is KtImportDirective)
computePackageFragmentToCheck(importDirective.containingKtFile, packageFragmentForVisibilityCheck)
else
null
if (importDirective.isAllUnder) {
val packageOrClassDescriptor = resolveToPackageOrClass(
@@ -227,10 +233,10 @@ class QualifiedExpressionResolver {
scopeForFirstPart = null, position = QualifierPosition.IMPORT
) ?: return null
if (packageOrClassDescriptor is ClassDescriptor && packageOrClassDescriptor.kind.isSingleton) {
if (packageOrClassDescriptor is ClassDescriptor && packageOrClassDescriptor.kind.isSingleton && lastPart.expression != null) {
trace.report(
Errors.CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON.on(
lastPart.expression,
lastPart.expression!!,
packageOrClassDescriptor
)
) // todo report on star
@@ -243,15 +249,33 @@ class QualifiedExpressionResolver {
}
}
private fun computePackageFragmentToCheck(
containingFile: KtFile,
packageFragmentForVisibilityCheck: PackageFragmentDescriptor?
): PackageFragmentDescriptor? =
when {
containingFile.suppressDiagnosticsInDebugMode() -> null
packageFragmentForVisibilityCheck is DeclarationDescriptorWithSource &&
packageFragmentForVisibilityCheck.source == SourceElement.NO_SOURCE -> {
PackageFragmentWithCustomSource(
packageFragmentForVisibilityCheck,
KotlinSourceElement(containingFile)
)
}
else -> packageFragmentForVisibilityCheck
}
private fun processSingleImport(
moduleDescriptor: ModuleDescriptor,
trace: BindingTrace,
importDirective: KtImportDirective,
importDirective: KtImportInfo,
path: List<QualifierPart>,
lastPart: QualifierPart,
packageFragmentForVisibilityCheck: PackageFragmentDescriptor?
): ImportingScope? {
val aliasName = KtPsiUtil.getAliasName(importDirective)
val aliasName = importDirective.importedName
if (aliasName == null) {
// import kotlin.
resolveToPackageOrClass(
@@ -301,13 +325,15 @@ class QualifiedExpressionResolver {
packageOrClassDescriptor: DeclarationDescriptor,
lastPart: QualifierPart
) {
val lastPartExpression = lastPart.expression ?: return
val descriptors = SmartList<DeclarationDescriptor>()
val lastName = lastPart.name
when (packageOrClassDescriptor) {
is PackageViewDescriptor -> {
val packageDescriptor = moduleDescriptor.getPackage(packageOrClassDescriptor.fqName.child(lastName))
if (!packageDescriptor.isEmpty()) {
trace.report(Errors.PACKAGE_CANNOT_BE_IMPORTED.on(lastPart.expression))
trace.report(Errors.PACKAGE_CANNOT_BE_IMPORTED.on(lastPartExpression))
descriptors.add(packageOrClassDescriptor)
}
}
@@ -317,7 +343,7 @@ class QualifiedExpressionResolver {
descriptors.addAll(memberScope.getContributedFunctions(lastName, lastPart.location))
descriptors.addAll(memberScope.getContributedVariables(lastName, lastPart.location))
if (descriptors.isNotEmpty()) {
trace.report(Errors.CANNOT_BE_IMPORTED.on(lastPart.expression, lastName))
trace.report(Errors.CANNOT_BE_IMPORTED.on(lastPartExpression, lastName))
}
}
@@ -333,18 +359,24 @@ class QualifiedExpressionResolver {
)
}
private fun KtExpression.asQualifierPartList(doubleColonLHS: Boolean = false): List<QualifierPart> {
val result = SmartList<QualifierPart>()
private fun KtImportInfo.ImportContent.asQualifierPartList(): List<QualifierPart> =
when (this) {
is KtImportInfo.ImportContent.ExpressionBased -> expression.asQualifierPartList()
is KtImportInfo.ImportContent.FqNameBased -> fqName.pathSegments().map { QualifierPart(it) }
}
private fun KtExpression.asQualifierPartList(doubleColonLHS: Boolean = false): List<ExpressionQualifierPart> {
val result = SmartList<ExpressionQualifierPart>()
fun addQualifierPart(expression: KtExpression?): Boolean {
if (expression is KtSimpleNameExpression) {
result.add(QualifierPart(expression))
result.add(ExpressionQualifierPart(expression))
return true
}
if (doubleColonLHS && expression is KtCallExpression && expression.isWithoutValueArguments) {
val simpleName = expression.calleeExpression
if (simpleName is KtSimpleNameExpression) {
result.add(QualifierPart(simpleName.getReferencedNameAsName(), simpleName, expression.typeArgumentList))
result.add(ExpressionQualifierPart(simpleName.getReferencedNameAsName(), simpleName, expression.typeArgumentList))
return true
}
}
@@ -364,16 +396,27 @@ class QualifiedExpressionResolver {
return result.asReversed()
}
data class QualifierPart(
open class QualifierPart(
val name: Name,
val expression: KtSimpleNameExpression,
val typeArguments: KtTypeArgumentList? = null
val typeArguments: KtTypeArgumentList? = null,
val location: LookupLocation = NoLookupLocation.FOR_DEFAULT_IMPORTS
) {
constructor (expression: KtSimpleNameExpression) : this(expression.getReferencedNameAsName(), expression)
open val expression: KtSimpleNameExpression? get() = null
val location = KotlinLookupLocation(expression)
operator fun component1() = name
open operator fun component2() = expression
operator fun component3() = typeArguments
}
class ExpressionQualifierPart(
name: Name,
override val expression: KtSimpleNameExpression,
typeArguments: KtTypeArgumentList? = null
) : QualifierPart(name, typeArguments, KotlinLookupLocation(expression)) {
constructor(expression: KtSimpleNameExpression) : this(expression.getReferencedNameAsName(), expression)
override fun component2() = expression
}
private fun resolveToPackageOrClass(
path: List<QualifierPart>,
@@ -412,7 +455,7 @@ class QualifiedExpressionResolver {
// In expression position, value wins against classifier (and package).
// If we see a function or variable (possibly ambiguous),
// tell resolver we have no qualifier and let it perform the context-dependent resolution.
if (scopeForFirstPart != null && isValue != null && isValue(firstPart.expression)) {
if (scopeForFirstPart != null && isValue != null && firstPart.expression != null && isValue(firstPart.expression!!)) {
return Pair(null, 0)
}
}
@@ -484,11 +527,11 @@ class QualifiedExpressionResolver {
is PackageQualifier -> {
val childPackageFQN = receiver.descriptor.fqName.child(name)
receiver.descriptor.module.getPackage(childPackageFQN).takeUnless { it.isEmpty() }
?: receiver.descriptor.memberScope.getContributedClassifier(name, location)
?: receiver.descriptor.memberScope.getContributedClassifier(name, location)
}
is ClassQualifier -> receiver.staticScope.getContributedClassifier(name, location)
null -> context.scope.findClassifier(name, location)
?: context.scope.ownerDescriptor.module.getPackage(FqName.ROOT.child(name)).takeUnless { it.isEmpty() }
?: context.scope.ownerDescriptor.module.getPackage(FqName.ROOT.child(name)).takeUnless { it.isEmpty() }
is ReceiverValue -> receiver.type.memberScope.memberScopeAsImportingScope().findClassifier(name, location)
else -> null
}
@@ -581,13 +624,13 @@ class QualifiedExpressionResolver {
// qualified expression 'a.b.c.d': qualifier parts == ['a', 'b', 'c']
val qualifierParts = arrayListOf<QualifierPart>()
qualifierParts.add(QualifierPart(firstReceiver))
qualifierParts.add(ExpressionQualifierPart(firstReceiver))
for (qualifiedExpression in qualifiedExpressions.dropLast(skipLast)) {
if (qualifiedExpression !is KtDotQualifiedExpression) break
val selector = qualifiedExpression.selectorExpression
if (selector !is KtSimpleNameExpression) break
qualifierParts.add(QualifierPart(selector))
qualifierParts.add(ExpressionQualifierPart(selector))
}
return qualifierParts
@@ -620,24 +663,25 @@ class QualifiedExpressionResolver {
trace: BindingTrace,
position: QualifierPosition
) {
path.foldRight(packageView) { (_, expression), currentView ->
storeResult(trace, expression, currentView, shouldBeVisibleFrom = null, position = position)
path.foldRight(packageView) { qualifierPart, currentView ->
storeResult(trace, qualifierPart.expression, currentView, shouldBeVisibleFrom = null, position = position)
currentView.containingDeclaration
?: error(
"Containing Declaration must be not null for package with fqName: ${currentView.fqName}, " +
"path: ${path.joinToString()}, packageView fqName: ${packageView.fqName}"
)
?: error(
"Containing Declaration must be not null for package with fqName: ${currentView.fqName}, " +
"path: ${path.joinToString()}, packageView fqName: ${packageView.fqName}"
)
}
}
private fun storeResult(
trace: BindingTrace,
referenceExpression: KtSimpleNameExpression,
referenceExpression: KtSimpleNameExpression?,
descriptors: Collection<DeclarationDescriptor>,
shouldBeVisibleFrom: DeclarationDescriptor?,
position: QualifierPosition,
isQualifier: Boolean = true
) {
referenceExpression ?: return
if (descriptors.size > 1) {
val visibleDescriptors = descriptors.filter { isVisible(it, shouldBeVisibleFrom, position) }
when {
@@ -659,12 +703,13 @@ class QualifiedExpressionResolver {
private fun storeResult(
trace: BindingTrace,
referenceExpression: KtSimpleNameExpression,
referenceExpression: KtSimpleNameExpression?,
descriptor: DeclarationDescriptor?,
shouldBeVisibleFrom: DeclarationDescriptor?,
position: QualifierPosition,
isQualifier: Boolean = true
): Qualifier? {
referenceExpression ?: return null
if (descriptor == null) {
trace.report(Errors.UNRESOLVED_REFERENCE.on(referenceExpression, referenceExpression))
return null
@@ -698,7 +698,7 @@ class TypeResolver(
private fun collectArgumentsForClassifierTypeConstructor(
c: TypeResolutionContext,
classifierDescriptor: ClassifierDescriptorWithTypeParameters,
qualifierParts: List<QualifiedExpressionResolver.QualifierPart>
qualifierParts: List<QualifiedExpressionResolver.ExpressionQualifierPart>
): Pair<List<KtTypeProjection>, List<TypeProjection>?>? {
val classifierDescriptorChain = classifierDescriptor.classifierDescriptorsFromInnerToOuter()
val reversedQualifierParts = qualifierParts.asReversed()
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtImportInfo
import org.jetbrains.kotlin.psi.KtImportsFactory
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.scopes.*
@@ -48,15 +49,19 @@ class FileScopeFactory(
private val languageVersionSettings: LanguageVersionSettings,
private val deprecationResolver: DeprecationResolver
) {
/* avoid constructing psi for default imports prematurely (time consuming in some scenarios) */
private val defaultImports by storageManager.createLazyValue {
ktImportsFactory.createImportDirectivesNotCached(
targetPlatform.getDefaultImports(languageVersionSettings, includeLowPriorityImports = false)
)
}
private val defaultImports =
targetPlatform.getDefaultImports(languageVersionSettings, includeLowPriorityImports = false).map(::DefaultImportImpl)
private val defaultLowPriorityImports by storageManager.createLazyValue {
ktImportsFactory.createImportDirectivesNotCached(targetPlatform.defaultLowPriorityImports)
private val defaultLowPriorityImports = targetPlatform.defaultLowPriorityImports.map(::DefaultImportImpl)
private class DefaultImportImpl(private val importPath: ImportPath) : KtImportInfo {
override val isAllUnder: Boolean get() = importPath.isAllUnder
override val importContent = KtImportInfo.ImportContent.FqNameBased(importPath.fqName)
override val aliasName: String? get() = importPath.alias?.asString()
override val importedFqName: FqName? get() = importPath.fqName
}
fun createScopesForFile(file: KtFile, existingImports: ImportingScope? = null): FileScopes {
@@ -73,7 +78,7 @@ class FileScopeFactory(
)
private fun createDefaultImportResolvers(
extraImports: Collection<KtImportDirective>,
extraImports: Collection<KtImportInfo>,
aliasImportNames: Collection<FqName>
): DefaultImportResolvers {
val tempTrace = TemporaryBindingTrace.create(bindingTrace, "Transient trace for default imports lazy resolve", false)
@@ -160,7 +165,7 @@ class FileScopeFactory(
allUnderImportResolver.forceResolveAllImports()
}
override fun forceResolveImport(importDirective: KtImportDirective) {
override fun forceResolveImport(importDirective: KtImportInfo) {
if (importDirective.isAllUnder) {
allUnderImportResolver.forceResolveImport(importDirective)
} else {
@@ -174,7 +179,7 @@ class FileScopeFactory(
private fun createDefaultImportResolversForFile(): DefaultImportResolvers {
val extraImports = file.takeIf { it.isScript() }?.originalFile?.virtualFile?.let { vFile ->
val scriptExternalDependencies = getScriptExternalDependencies(vFile, file.project)
ktImportsFactory.createImportDirectives(scriptExternalDependencies?.imports?.map { ImportPath.fromString(it) }.orEmpty())
scriptExternalDependencies?.imports?.map { DefaultImportImpl(ImportPath.fromString(it)) }.orEmpty()
}.orEmpty()
if (extraImports.isEmpty() && aliasImportNames.isEmpty()) {
@@ -25,9 +25,11 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtImportInfo
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
@@ -41,24 +43,23 @@ import org.jetbrains.kotlin.utils.addToStdlib.flatMapToNullable
import org.jetbrains.kotlin.utils.ifEmpty
interface IndexedImports {
val imports: List<KtImportDirective>
fun importsForName(name: Name): Collection<KtImportDirective>
val imports: List<KtImportInfo>
fun importsForName(name: Name): Collection<KtImportInfo>
}
class AllUnderImportsIndexed(allImports: Collection<KtImportDirective>) : IndexedImports {
class AllUnderImportsIndexed(allImports: Collection<KtImportInfo>) : IndexedImports {
override val imports = allImports.filter { it.isAllUnder }
override fun importsForName(name: Name) = imports
}
class ExplicitImportsIndexed(allImports: Collection<KtImportDirective>) : IndexedImports {
class ExplicitImportsIndexed(allImports: Collection<KtImportInfo>) : IndexedImports {
override val imports = allImports.filter { !it.isAllUnder }
private val nameToDirectives: ListMultimap<Name, KtImportDirective> by lazy {
val builder = ImmutableListMultimap.builder<Name, KtImportDirective>()
private val nameToDirectives: ListMultimap<Name, KtImportInfo> by lazy {
val builder = ImmutableListMultimap.builder<Name, KtImportInfo>()
for (directive in imports) {
val path = directive.importPath ?: continue // parse error
val importedName = path.importedName ?: continue // parse error
val importedName = directive.importedName ?: continue // parse error
builder.put(importedName, directive)
}
@@ -70,7 +71,7 @@ class ExplicitImportsIndexed(allImports: Collection<KtImportDirective>) : Indexe
interface ImportResolver {
fun forceResolveAllImports()
fun forceResolveImport(importDirective: KtImportDirective)
fun forceResolveImport(importDirective: KtImportInfo)
}
class LazyImportResolver(
@@ -85,41 +86,48 @@ class LazyImportResolver(
private val packageFragment: PackageFragmentDescriptor?,
val deprecationResolver: DeprecationResolver
) : ImportResolver {
private val importedScopesProvider = storageManager.createMemoizedFunctionWithNullableValues { directive: KtImportDirective ->
private val importedScopesProvider = storageManager.createMemoizedFunctionWithNullableValues { directive: KtImportInfo ->
qualifiedExpressionResolver.processImportReference(
directive, moduleDescriptor, traceForImportResolve, excludedImportNames, packageFragment
)
}
private val forceResolveImportDirective = storageManager.createMemoizedFunction { directive: KtImportDirective ->
private val forceResolveImportDirective = storageManager.createMemoizedFunction { directive: KtImportInfo ->
val scope = importedScopesProvider(directive)
if (scope is LazyExplicitImportScope) {
val allDescriptors = scope.storeReferencesToDescriptors()
PlatformClassesMappedToKotlinChecker.checkPlatformClassesMappedToKotlin(
platformToKotlinClassMap, traceForImportResolve, directive, allDescriptors
)
if (directive is KtImportDirective) {
PlatformClassesMappedToKotlinChecker.checkPlatformClassesMappedToKotlin(
platformToKotlinClassMap, traceForImportResolve, directive, allDescriptors
)
}
}
Unit
}
private val forceResolveAllImportsTask: NotNullLazyValue<Unit> = storageManager.createLazyValue {
val explicitClassImports = HashMultimap.create<String, KtImportDirective>()
val explicitClassImports = HashMultimap.create<String, KtImportInfo>()
for (importDirective in indexedImports.imports) {
forceResolveImport(importDirective)
val scope = importedScopesProvider(importDirective)
val alias = KtPsiUtil.getAliasName(importDirective)?.identifier
val alias = importDirective.importedName
if (scope != null && alias != null) {
if (scope.getContributedClassifier(Name.identifier(alias), KotlinLookupLocation(importDirective)) != null) {
explicitClassImports.put(alias, importDirective)
val lookupLocation = when (importDirective) {
is KtImportDirective -> KotlinLookupLocation(importDirective)
else -> NoLookupLocation.FOR_DEFAULT_IMPORTS
}
if (scope.getContributedClassifier(alias, lookupLocation) != null) {
explicitClassImports.put(alias.asString(), importDirective)
}
}
checkResolvedImportDirective(importDirective)
}
for ((alias, import) in explicitClassImports.entries()) {
if (import !is KtImportDirective) continue
if (alias.all { it == '_' }) {
traceForImportResolve.report(Errors.UNDERSCORE_IS_RESERVED.on(import))
}
@@ -127,7 +135,7 @@ class LazyImportResolver(
for (alias in explicitClassImports.keySet()) {
val imports = explicitClassImports.get(alias)
if (imports.size > 1) {
imports.forEach {
imports.filterIsInstance<KtImportDirective>().forEach {
traceForImportResolve.report(Errors.CONFLICTING_IMPORT.on(it, alias))
}
}
@@ -138,7 +146,8 @@ class LazyImportResolver(
forceResolveAllImportsTask()
}
private fun checkResolvedImportDirective(importDirective: KtImportDirective) {
private fun checkResolvedImportDirective(importDirective: KtImportInfo) {
if (importDirective !is KtImportDirective) return
val importedReference = KtPsiUtil.getLastReference(importDirective.importedReference ?: return) ?: return
val importedDescriptor = traceForImportResolve.bindingContext.get(BindingContext.REFERENCE_TARGET, importedReference) ?: return
@@ -150,7 +159,7 @@ class LazyImportResolver(
}
}
override fun forceResolveImport(importDirective: KtImportDirective) {
override fun forceResolveImport(importDirective: KtImportInfo) {
forceResolveImportDirective(importDirective)
}
@@ -187,7 +196,7 @@ class LazyImportResolver(
}
}
fun getImportScope(directive: KtImportDirective): ImportingScope {
fun getImportScope(directive: KtImportInfo): ImportingScope {
return importedScopesProvider(directive) ?: ImportingScope.Empty
}
@@ -278,8 +287,7 @@ class LazyImportScope(
val importedNames = if (secondaryImportResolver == null) null else hashSetOf<Name>()
for (directive in importResolver.indexedImports.imports) {
val importPath = directive.importPath ?: continue
val importedName = importPath.importedName
val importedName = directive.importedName
if (importedName == null || nameFilter(importedName)) {
val newDescriptors =
importResolver.getImportScope(directive).getContributedDescriptors(kindFilter, nameFilter, changeNamesForAliased)
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.psi.stubs.KotlinImportDirectiveStub;
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
import org.jetbrains.kotlin.resolve.ImportPath;
public class KtImportDirective extends KtElementImplStub<KotlinImportDirectiveStub> {
public class KtImportDirective extends KtElementImplStub<KotlinImportDirectiveStub> implements KtImportInfo {
public KtImportDirective(@NotNull ASTNode node) {
super(node);
@@ -59,12 +59,14 @@ public class KtImportDirective extends KtElementImplStub<KotlinImportDirectiveSt
return getStubOrPsiChild(KtStubElementTypes.IMPORT_ALIAS);
}
@Override
@Nullable
public String getAliasName() {
KtImportAlias alias = getAlias();
return alias != null ? alias.getName() : null;
}
@Override
public boolean isAllUnder() {
KotlinImportDirectiveStub stub = getStub();
if (stub != null) {
@@ -73,6 +75,21 @@ public class KtImportDirective extends KtElementImplStub<KotlinImportDirectiveSt
return getNode().findChildByType(KtTokens.MUL) != null;
}
@Nullable
@Override
public ImportContent getImportContent() {
KtExpression reference = getImportedReference();
if (reference == null) return null;
return new ImportContent.ExpressionBased(reference);
}
@Nullable
@Override
public Name getImportedName() {
return KtImportInfo.DefaultImpls.getImportedName(this);
}
@Override
@Nullable
@IfNotParsed
public FqName getImportedFqName() {
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.psi
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
interface KtImportInfo {
sealed class ImportContent {
class ExpressionBased(val expression: KtExpression) : ImportContent()
class FqNameBased(val fqName: FqName) : ImportContent()
}
val isAllUnder: Boolean
val importContent: ImportContent?
val importedFqName: FqName?
val aliasName: String?
val importedName: Name?
get() {
return computeNameAsString()?.takeIf(CharSequence::isNotEmpty)?.let(Name::identifier)
}
private fun computeNameAsString(): String? {
if (isAllUnder) return null
aliasName?.let { return it }
val importContent = importContent
return when (importContent) {
is ImportContent.ExpressionBased -> KtPsiUtil.getLastReference(importContent.expression)?.getReferencedName()
is ImportContent.FqNameBased -> importContent.fqName.takeUnless(FqName::isRoot)?.shortName()?.asString()
null -> null
}
}
}
@@ -30,7 +30,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.KtNodeTypes;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.kdoc.psi.api.KDocElement;
import org.jetbrains.kotlin.lexer.KtToken;
import org.jetbrains.kotlin.lexer.KtTokens;
@@ -224,24 +223,6 @@ public class KtPsiUtil {
return null;
}
@Nullable
public static Name getAliasName(@NotNull KtImportDirective importDirective) {
if (importDirective.isAllUnder()) {
return null;
}
String aliasName = importDirective.getAliasName();
KtExpression importedReference = importDirective.getImportedReference();
if (importedReference == null) {
return null;
}
KtSimpleNameExpression referenceExpression = getLastReference(importedReference);
if (aliasName == null) {
aliasName = referenceExpression != null ? referenceExpression.getReferencedName() : null;
}
return aliasName != null && !aliasName.isEmpty() ? Name.identifier(aliasName) : null;
}
@Nullable
public static KtSimpleNameExpression getLastReference(@NotNull KtExpression importedReference) {
KtElement selector = KtPsiUtilKt.getQualifiedElementSelector(importedReference);
@@ -58,7 +58,8 @@ enum class NoLookupLocation : LookupLocation {
FROM_JAVA_LOADER,
WHEN_GET_LOCAL_VARIABLE,
WHEN_FIND_BY_FQNAME,
WHEN_GET_COMPANION_OBJECT;
WHEN_GET_COMPANION_OBJECT,
FOR_DEFAULT_IMPORTS;
override val location: LocationInfo? get() = null
}