Avoid creating fake PSI for default imports
#KT-13860 Fixed
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user