J2K ImportPath: kotlinify

This commit is contained in:
Pavel V. Talanov
2017-02-13 13:16:11 +03:00
parent 50d0f5bde6
commit babb3b557d
16 changed files with 45 additions and 77 deletions
@@ -28,8 +28,8 @@ object JvmPlatform : TargetPlatform("JVM") {
override fun getDefaultImports(languageVersionSettings: LanguageVersionSettings): List<ImportPath> = ArrayList<ImportPath>().apply { override fun getDefaultImports(languageVersionSettings: LanguageVersionSettings): List<ImportPath> = ArrayList<ImportPath>().apply {
addAll(Default.getDefaultImports(languageVersionSettings)) addAll(Default.getDefaultImports(languageVersionSettings))
add(ImportPath("java.lang.*")) add(ImportPath.fromString("java.lang.*"))
add(ImportPath("kotlin.jvm.*")) add(ImportPath.fromString("kotlin.jvm.*"))
fun addAllClassifiersFromScope(scope: MemberScope) { fun addAllClassifiersFromScope(scope: MemberScope) {
for (descriptor in scope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS, MemberScope.ALL_NAME_FILTER)) { for (descriptor in scope.getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS, MemberScope.ALL_NAME_FILTER)) {
@@ -384,7 +384,7 @@ class KtPsiFactory(private val project: Project) {
} }
fun createImportDirective(importPath: ImportPath): KtImportDirective { fun createImportDirective(importPath: ImportPath): KtImportDirective {
if (importPath.fqnPart().isRoot) { if (importPath.fqName.isRoot) {
throw IllegalArgumentException("import path must not be empty") throw IllegalArgumentException("import path must not be empty")
} }
@@ -20,29 +20,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.renderer.* import org.jetbrains.kotlin.renderer.*
class ImportPath { data class ImportPath @JvmOverloads constructor(val fqName: FqName, val isAllUnder: Boolean, val alias: Name? = null) {
private val fqName: FqName
val alias: Name?
val isAllUnder: Boolean
@JvmOverloads constructor(fqName: FqName, isAllUnder: Boolean, alias: Name? = null) {
this.fqName = fqName
this.isAllUnder = isAllUnder
this.alias = alias
}
constructor(pathStr: String) {
if (pathStr.endsWith(".*")) {
this.isAllUnder = true
this.fqName = FqName(pathStr.substring(0, pathStr.length - 2))
}
else {
this.isAllUnder = false
this.fqName = FqName(pathStr)
}
alias = null
}
val pathStr: String val pathStr: String
get() = fqName.toUnsafe().render() + if (isAllUnder) ".*" else "" get() = fqName.toUnsafe().render() + if (isAllUnder) ".*" else ""
@@ -51,10 +29,6 @@ class ImportPath {
return pathStr + if (alias != null) " as " + alias.asString() else "" return pathStr + if (alias != null) " as " + alias.asString() else ""
} }
fun fqnPart(): FqName {
return fqName
}
fun hasAlias(): Boolean { fun hasAlias(): Boolean {
return alias != null return alias != null
} }
@@ -68,23 +42,15 @@ class ImportPath {
return null return null
} }
override fun equals(o: Any?): Boolean { companion object {
if (this === o) return true @JvmStatic fun fromString(pathStr: String): ImportPath {
if (o == null || javaClass != o.javaClass) return false if (pathStr.endsWith(".*")) {
return ImportPath(FqName(pathStr.substring(0, pathStr.length - 2)), isAllUnder = true)
}
else {
return ImportPath(FqName(pathStr), isAllUnder = false)
val path = o as ImportPath? }
}
if (isAllUnder != path!!.isAllUnder) return false
if (if (alias != null) alias != path.alias else path.alias != null) return false
if (fqName != path.fqName) return false
return true
}
override fun hashCode(): Int {
var result = fqName.hashCode()
result = 31 * result + (alias?.hashCode() ?: 0)
result = 31 * result + if (isAllUnder) 1 else 0
return result
} }
} }
@@ -43,16 +43,18 @@ abstract class TargetPlatform(val platformName: String) {
object Default : TargetPlatform("Default") { object Default : TargetPlatform("Default") {
override fun getDefaultImports(languageVersionSettings: LanguageVersionSettings): List<ImportPath> = ArrayList<ImportPath>().apply { override fun getDefaultImports(languageVersionSettings: LanguageVersionSettings): List<ImportPath> = ArrayList<ImportPath>().apply {
add(ImportPath("kotlin.*")) listOf(
add(ImportPath("kotlin.annotation.*")) "kotlin.*",
add(ImportPath("kotlin.collections.*")) "kotlin.annotation.*",
add(ImportPath("kotlin.ranges.*")) "kotlin.collections.*",
add(ImportPath("kotlin.sequences.*")) "kotlin.ranges.*",
add(ImportPath("kotlin.text.*")) "kotlin.sequences.*",
add(ImportPath("kotlin.io.*")) "kotlin.text.*",
"kotlin.io.*"
).forEach { add(ImportPath.fromString(it)) }
if (languageVersionSettings.supportsFeature(LanguageFeature.DefaultImportOfPackageKotlinComparisons)) { if (languageVersionSettings.supportsFeature(LanguageFeature.DefaultImportOfPackageKotlinComparisons)) {
add(ImportPath("kotlin.comparisons.*")) add(ImportPath.fromString("kotlin.comparisons.*"))
} }
} }
@@ -55,7 +55,7 @@ class DefaultImportProvider(
defaultImports defaultImports
.filter { it.isAllUnder } .filter { it.isAllUnder }
.mapNotNull { .mapNotNull {
it.fqnPart().takeIf { !it.isSubpackageOf(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME) } it.fqName.takeIf { !it.isSubpackageOf(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME) }
} }
val nonKotlinAliasedTypeFqNames = val nonKotlinAliasedTypeFqNames =
builtinTypeAliases builtinTypeAliases
@@ -71,7 +71,7 @@ class FileScopeFactory(
val extraImports = file.originalFile.virtualFile?.let { vFile -> val extraImports = file.originalFile.virtualFile?.let { vFile ->
val scriptExternalDependencies = getScriptExternalDependencies(vFile, file.project) val scriptExternalDependencies = getScriptExternalDependencies(vFile, file.project)
ktImportsFactory.createImportDirectives(scriptExternalDependencies?.imports?.map(::ImportPath).orEmpty()) ktImportsFactory.createImportDirectives(scriptExternalDependencies?.imports?.map { ImportPath.fromString(it) }.orEmpty())
} }
val allImplicitImports = defaultImports concat extraImports val allImplicitImports = defaultImports concat extraImports
@@ -91,7 +91,7 @@ class OptimizedImportsBuilder(
.mapNotNull { it.importPath } .mapNotNull { it.importPath }
.filter { .filter {
val aliasName = it.alias val aliasName = it.alias
aliasName != null && aliasName != it.fqnPart().shortName() aliasName != null && aliasName != it.fqName.shortName()
} }
.mapTo(importRules) { ImportRule.Add(it) } .mapTo(importRules) { ImportRule.Add(it) }
@@ -48,7 +48,7 @@ private fun KtFile.buildAliasImportMap(): Multimap<String, String> {
val importList = importList ?: return map val importList = importList ?: return map
for (import in importList.imports) { for (import in importList.imports) {
val aliasName = import.aliasName ?: continue val aliasName = import.aliasName ?: continue
val name = import.importPath?.fqnPart()?.shortName()?.asString() ?: continue val name = import.importPath?.fqName?.shortName()?.asString() ?: continue
map.put(aliasName, name) map.put(aliasName, name)
} }
return map return map
@@ -45,17 +45,17 @@ fun PsiElement.getKotlinFqName(): FqName? {
fun FqName.isImported(importPath: ImportPath, skipAliasedImports: Boolean = true): Boolean { fun FqName.isImported(importPath: ImportPath, skipAliasedImports: Boolean = true): Boolean {
return when { return when {
skipAliasedImports && importPath.hasAlias() -> false skipAliasedImports && importPath.hasAlias() -> false
importPath.isAllUnder && !isRoot -> importPath.fqnPart() == this.parent() importPath.isAllUnder && !isRoot -> importPath.fqName == this.parent()
else -> importPath.fqnPart() == this else -> importPath.fqName == this
} }
} }
fun ImportPath.isImported(alreadyImported: ImportPath): Boolean { fun ImportPath.isImported(alreadyImported: ImportPath): Boolean {
return if (isAllUnder || hasAlias()) this == alreadyImported else fqnPart().isImported(alreadyImported) return if (isAllUnder || hasAlias()) this == alreadyImported else fqName.isImported(alreadyImported)
} }
private fun ImportPath.isImported(imports: Iterable<ImportPath>): Boolean = imports.any { isImported(it) } private fun ImportPath.isImported(imports: Iterable<ImportPath>): Boolean = imports.any { isImported(it) }
fun ImportPath.isImported(imports: Iterable<ImportPath>, excludedFqNames: Iterable<FqName>): Boolean { fun ImportPath.isImported(imports: Iterable<ImportPath>, excludedFqNames: Iterable<FqName>): Boolean {
return isImported(imports) && (isAllUnder || this.fqnPart() !in excludedFqNames) return isImported(imports) && (isAllUnder || this.fqName !in excludedFqNames)
} }
@@ -391,7 +391,7 @@ fun LookupElement.decorateAsStaticMember(
val psiDocumentManager = PsiDocumentManager.getInstance(context.project) val psiDocumentManager = PsiDocumentManager.getInstance(context.project)
val file = context.file as KtFile val file = context.file as KtFile
val addMemberImport = file.importDirectives.any { !it.isAllUnder && it.importPath?.fqnPart()?.parent() == containerFqName } val addMemberImport = file.importDirectives.any { !it.isAllUnder && it.importPath?.fqName?.parent() == containerFqName }
if (addMemberImport) { if (addMemberImport) {
psiDocumentManager.commitAllDocuments() psiDocumentManager.commitAllDocuments()
@@ -34,7 +34,7 @@ class ImportableFqNameClassifier(private val file: KtFile) {
init { init {
for (import in file.importDirectives) { for (import in file.importDirectives) {
val importPath = import.importPath ?: continue val importPath = import.importPath ?: continue
val fqName = importPath.fqnPart() val fqName = importPath.fqName
if (importPath.isAllUnder) { if (importPath.isAllUnder) {
allUnderImports.add(fqName) allUnderImports.add(fqName)
} }
@@ -66,7 +66,7 @@ class KotlinUnusedImportInspection : AbstractKotlinInspection() {
.asSequence() .asSequence()
.mapNotNull { it.importPath } .mapNotNull { it.importPath }
.filter { !it.isAllUnder && !it.hasAlias() } .filter { !it.isAllUnder && !it.hasAlias() }
.map { it.fqnPart() } .map { it.fqName }
.toSet() .toSet()
val fqNames = HashSet<FqName>() val fqNames = HashSet<FqName>()
@@ -95,10 +95,10 @@ class KotlinUnusedImportInspection : AbstractKotlinInspection() {
false false
} }
else if (importPath.isAllUnder) { else if (importPath.isAllUnder) {
importPath.fqnPart() in parentFqNames importPath.fqName in parentFqNames
} }
else { else {
importPath.fqnPart() in fqNames importPath.fqName in fqNames
} }
if (!isUsed) { if (!isUsed) {
@@ -134,8 +134,8 @@ object ReplaceWithAnnotationAnalyzer {
// this solution doesn't support aliased default imports with a different alias // this solution doesn't support aliased default imports with a different alias
// TODO: Create import directives from ImportPath, create ImportResolver, create LazyResolverScope, see FileScopeProviderImpl // TODO: Create import directives from ImportPath, create ImportResolver, create LazyResolverScope, see FileScopeProviderImpl
return listOf(buildExplicitImportsScope(aliasImports.map { it.fqnPart() }, resolutionFacade, module)) + return listOf(buildExplicitImportsScope(aliasImports.map { it.fqName }, resolutionFacade, module)) +
allUnderImports.map { module.getPackage(it.fqnPart()).memberScope.memberScopeAsImportingScope() }.asReversed() allUnderImports.map { module.getPackage(it.fqName).memberScope.memberScopeAsImportingScope() }.asReversed()
} }
private fun buildExplicitImportsScope(annotation: ReplaceWith, resolutionFacade: ResolutionFacade, module: ModuleDescriptor): ExplicitImportsScope { private fun buildExplicitImportsScope(annotation: ReplaceWith, resolutionFacade: ResolutionFacade, module: ModuleDescriptor): ExplicitImportsScope {
@@ -121,7 +121,7 @@ class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper(
val imports = file.importDirectives val imports = file.importDirectives
if (imports.any { !it.isAllUnder && it.importPath?.fqnPart() == targetFqName }) { if (imports.any { !it.isAllUnder && it.importPath?.fqName == targetFqName }) {
return ImportDescriptorResult.FAIL return ImportDescriptorResult.FAIL
} }
@@ -132,7 +132,7 @@ class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper(
else -> null else -> null
} }
if (conflict != null if (conflict != null
&& imports.any { !it.isAllUnder && it.importPath?.fqnPart() == conflict.importableFqName && it.importPath?.importedName == name } && imports.any { !it.isAllUnder && it.importPath?.fqName == conflict.importableFqName && it.importPath?.importedName == name }
) { ) {
return ImportDescriptorResult.FAIL return ImportDescriptorResult.FAIL
} }
@@ -187,7 +187,7 @@ class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper(
val importsFromPackage = imports.count { val importsFromPackage = imports.count {
val path = it.importPath val path = it.importPath
path != null && !path.isAllUnder && !path.hasAlias() && path.fqnPart().parent() == containerFqName path != null && !path.isAllUnder && !path.hasAlias() && path.fqName.parent() == containerFqName
} }
val nameCountToUseStar = if (target.containingDeclaration is ClassDescriptor) val nameCountToUseStar = if (target.containingDeclaration is ClassDescriptor)
codeStyleSettings.NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS codeStyleSettings.NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS
@@ -217,7 +217,7 @@ class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper(
.mapNotNull { .mapNotNull {
val importPath = it.importPath val importPath = it.importPath
if (importPath != null) { if (importPath != null) {
val fqName = importPath.fqnPart() val fqName = importPath.fqName
getMemberScope(fqName, moduleDescriptor) getMemberScope(fqName, moduleDescriptor)
} }
else { else {
@@ -300,7 +300,7 @@ class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper(
private fun dropRedundantExplicitImports(packageFqName: FqName) { private fun dropRedundantExplicitImports(packageFqName: FqName) {
val dropCandidates = file.importDirectives.filter { val dropCandidates = file.importDirectives.filter {
!it.isAllUnder && it.aliasName == null && it.importPath?.fqnPart()?.parent() == packageFqName !it.isAllUnder && it.aliasName == null && it.importPath?.fqName?.parent() == packageFqName
} }
val importsToCheck = ArrayList<FqName>() val importsToCheck = ArrayList<FqName>()
@@ -163,7 +163,7 @@ private fun renderImportName(fqName: FqName, isOnDemand: Boolean)
// TODO: use the correct LanguageVersionSettings instance here // TODO: use the correct LanguageVersionSettings instance here
private val DEFAULT_IMPORTS_SET: Set<FqName> = JvmPlatform.getDefaultImports(LanguageVersionSettingsImpl.DEFAULT) private val DEFAULT_IMPORTS_SET: Set<FqName> = JvmPlatform.getDefaultImports(LanguageVersionSettingsImpl.DEFAULT)
.filter { it.isAllUnder } .filter { it.isAllUnder }
.map { it.fqnPart() } .map { it.fqName }
.toSet() .toSet()
private fun isImportedByDefault(c: KtLightClass) = c.qualifiedName?.let { FqName(it).parent() } in DEFAULT_IMPORTS_SET private fun isImportedByDefault(c: KtLightClass) = c.qualifiedName?.let { FqName(it).parent() } in DEFAULT_IMPORTS_SET
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.resolve.TargetPlatform
object JsPlatform : TargetPlatform("JS") { object JsPlatform : TargetPlatform("JS") {
override fun getDefaultImports(languageVersionSettings: LanguageVersionSettings): List<ImportPath> = override fun getDefaultImports(languageVersionSettings: LanguageVersionSettings): List<ImportPath> =
Default.getDefaultImports(languageVersionSettings) + ImportPath("kotlin.js.*") Default.getDefaultImports(languageVersionSettings) + ImportPath.fromString("kotlin.js.*")
override val platformConfigurator: PlatformConfigurator = JsPlatformConfigurator override val platformConfigurator: PlatformConfigurator = JsPlatformConfigurator