Import is placed in some specific order on adding

This commit is contained in:
Valentin Kipyatkov
2015-02-13 01:07:40 +03:00
parent 371e0baed1
commit 0a363fc371
51 changed files with 126 additions and 74 deletions
@@ -40,9 +40,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.imports.importableFqName
import java.util.LinkedHashSet
import org.jetbrains.kotlin.idea.imports.importableFqNameSafe import org.jetbrains.kotlin.idea.imports.importableFqNameSafe
import java.util.ArrayList
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
@@ -55,6 +53,7 @@ import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.idea.util.ImportInsertHelper.ImportDescriptorResult import org.jetbrains.kotlin.idea.util.ImportInsertHelper.ImportDescriptorResult
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.idea.refactoring.fqName.isImported import org.jetbrains.kotlin.idea.refactoring.fqName.isImported
import java.util.*
public class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper() { public class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper() {
@@ -68,7 +67,7 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert
} }
} }
private fun writeImportToFile(importPath: ImportPath, file: JetFile): JetImportDirective { private fun addImport(file: JetFile, importPath: ImportPath): JetImportDirective {
val psiFactory = JetPsiFactory(project) val psiFactory = JetPsiFactory(project)
if (file is JetCodeFragment) { if (file is JetCodeFragment) {
val newDirective = psiFactory.createImportDirective(importPath) val newDirective = psiFactory.createImportDirective(importPath)
@@ -79,21 +78,53 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert
val importList = file.getImportList() val importList = file.getImportList()
if (importList != null) { if (importList != null) {
val newDirective = psiFactory.createImportDirective(importPath) val newDirective = psiFactory.createImportDirective(importPath)
importList.add(psiFactory.createNewLine()) val imports = importList.getImports()
return importList.add(newDirective) as JetImportDirective if (imports.isEmpty()) { //TODO: strange hack
importList.add(psiFactory.createNewLine())
return importList.add(newDirective) as JetImportDirective
}
else {
val insertAfter = imports
.reverse()
.firstOrNull {
val directivePath = it.getImportPath()
directivePath != null && ImportPathComparator.compare(directivePath, importPath) <= 0
}
return importList.addAfter(newDirective, insertAfter) as JetImportDirective
}
} }
else { else {
val newImportList = psiFactory.createImportDirectiveWithImportList(importPath) val newImportList = psiFactory.createImportDirectiveWithImportList(importPath)
val packageDirective = file.getPackageDirective() val packageDirective = file.getPackageDirective()
if (packageDirective == null) { ?: throw IllegalStateException("Scripts are not supported: " + file.getName())
throw IllegalStateException("Scripts are not supported: " + file.getName())
}
val addedImportList = packageDirective.getParent().addAfter(newImportList, packageDirective) as JetImportList val addedImportList = packageDirective.getParent().addAfter(newImportList, packageDirective) as JetImportList
return addedImportList.getImports().single() return addedImportList.getImports().single()
} }
} }
private object ImportPathComparator : Comparator<ImportPath> {
override fun compare(import1: ImportPath, import2: ImportPath): Int {
// alias imports placed last
if (import1.hasAlias() != import2.hasAlias()) {
return if (import1.hasAlias()) +1 else -1
}
// standard library imports last
val stdlib1 = isJavaOrKotlinStdlibImport(import1)
val stdlib2 = isJavaOrKotlinStdlibImport(import2)
if (stdlib1 != stdlib2) {
return if (stdlib1) +1 else -1
}
return import1.toString().compareTo(import2.toString())
}
private fun isJavaOrKotlinStdlibImport(path: ImportPath): Boolean {
val s = path.getPathStr()
return s.startsWith("java.") || s.startsWith("javax.")|| s.startsWith("kotlin.")
}
}
/** /**
* Check that import is useless. * Check that import is useless.
*/ */
@@ -383,7 +414,7 @@ public class ImportInsertHelperImpl(private val project: Project) : ImportInsert
} }
private fun addImport(fqName: FqName, allUnder: Boolean): JetImportDirective { private fun addImport(fqName: FqName, allUnder: Boolean): JetImportDirective {
return writeImportToFile(ImportPath(fqName, allUnder), file) return addImport(file, ImportPath(fqName, allUnder))
} }
} }
} }
@@ -2,7 +2,7 @@
package p package p
import java.sql.* import java.sql.*
import java.util.*
import java.sql.Date import java.sql.Date
import java.util.*
val d = Date() val d = Date()
@@ -2,7 +2,7 @@
package p package p
import java.sql.* import java.sql.*
import java.util.*
import java.sql.Date import java.sql.Date
import java.util.*
val d: Date? = null val d: Date? = null
@@ -2,7 +2,7 @@
package p package p
import dependency.* import dependency.*
import java.util.*
import dependency.Date import dependency.Date
import java.util.*
val d = Date(1, 2) val d = Date(1, 2)
@@ -2,7 +2,7 @@
package p package p
import dependency.* import dependency.*
import java.util.*
import dependency.Date import dependency.Date
import java.util.*
val d = Date.VALUE val d = Date.VALUE
@@ -2,7 +2,7 @@
package p package p
import dependency.AClass.* import dependency.AClass.*
import java.util.*
import dependency.AClass.Date import dependency.AClass.Date
import java.util.*
val d = Date() val d = Date()
@@ -3,7 +3,7 @@ package p
import java.sql.* import java.sql.*
import dependency.Date // import of function does not affect class name conflict import dependency.Date // import of function does not affect class name conflict
import java.util.*
import java.sql.Date import java.sql.Date
import java.util.*
val d = Date(1) val d = Date(1)
@@ -1,5 +1,5 @@
// IMPORT: java.sql.Date // IMPORT: java.sql.Date
package p package p
import java.util.*
import java.sql.Date import java.sql.Date
import java.util.*
@@ -1,6 +1,6 @@
// IMPORT: dependency.Date // IMPORT: dependency.Date
package p package p
import dependency.Date
import java.util.* import java.util.*
import java.sql.* import java.sql.*
import dependency.Date
@@ -2,10 +2,10 @@
package p package p
import java.sql.* import java.sql.*
import java.util.HashSet as JavaHashSet // alias import should not be dropped
import java.util.concurrent // import of package should not be dropped because packages are not imported by *
import java.util.* import java.util.*
import java.util.Date import java.util.Date
import java.util.HashSet as JavaHashSet // alias import should not be dropped
import java.util.concurrent // import of package should not be dropped because packages are not imported by *
fun foo() { fun foo() {
val v1 = JavaHashSet() val v1 = JavaHashSet()
@@ -1,7 +1,7 @@
// IMPORT: dependency.X // IMPORT: dependency.X
package p package p
import java.util.*
import dependency.* import dependency.*
import java.util.*
val d = Date(1, 2) val d = Date(1, 2)
@@ -0,0 +1,3 @@
package xxx
trait Dependency
@@ -0,0 +1,6 @@
// IMPORT: xxx.Dependency
import a.*
import kotlin.math.*
import java.util.*
import javax.*
@@ -0,0 +1,7 @@
// IMPORT: xxx.Dependency
import a.*
import xxx.*
import kotlin.math.*
import java.util.*
import javax.*
@@ -1,8 +1,8 @@
package foo package foo
import java.util.ArrayList
import bar.Other
import bar.Bar import bar.Bar
import bar.Other
import java.util.ArrayList
class Impl: Foo() { class Impl: Foo() {
override fun foo(list: ArrayList<Int>?, other: Other?): Bar? { override fun foo(list: ArrayList<Int>?, other: Other?): Bar? {
@@ -1,7 +1,7 @@
package some package some
import java.util.SortedSet
import jettesting.data.somefun import jettesting.data.somefun
import java.util.SortedSet
fun other() { fun other() {
somefun(<caret>) somefun(<caret>)
@@ -1,8 +1,8 @@
package to package to
import a.T
import a.A import a.A
import a.B import a.B
import a.T
fun g(t: T): Int { fun g(t: T): Int {
g(A) g(A)
@@ -1,8 +1,8 @@
package to package to
import a.A
import a.get import a.get
import a.set import a.set
import a.A
class B { class B {
var v by A() var v by A()
@@ -1,15 +1,15 @@
package to package to
import d.ext
import d.A import d.A
import d.T import d.ClassObject
import d.Outer import d.E
import d.c
import d.g
import d.O1 import d.O1
import d.O2 import d.O2
import d.E import d.Outer
import d.ClassObject import d.T
import d.c
import d.ext
import d.g
fun f(a: A, t: T) { fun f(a: A, t: T) {
g(A(c).ext()) g(A(c).ext())
@@ -1,8 +1,8 @@
package to package to
import a.f import a.f
import a.p
import a.g import a.g
import a.p
fun foo() { fun foo() {
3.f() 3.f()
@@ -1,8 +1,8 @@
package to package to
import a.plus
import a.infix
import a.A import a.A
import a.infix
import a.plus
fun f(a: A) { fun f(a: A) {
a + a a + a
@@ -2,10 +2,10 @@ package to
import a.A import a.A
import a.ext import a.ext
import a.plus
import a.infix import a.infix
import a.minus import a.minus
import a.p import a.p
import a.plus
fun A.ext() { fun A.ext() {
} }
@@ -1,9 +1,9 @@
package to package to
import a.A
import a.hasNext
import a.iterator import a.iterator
import a.next import a.next
import a.hasNext
import a.A
fun f() { fun f() {
for (i in A()) { for (i in A()) {
@@ -1,7 +1,7 @@
package to package to
import a.get
import a.A import a.A
import a.get
fun f() { fun f() {
A()[""] A()[""]
@@ -1,15 +1,15 @@
package to package to
import d.ext
import d.A import d.A
import d.T import d.ClassObject
import d.Outer import d.E
import d.c
import d.g
import d.O1 import d.O1
import d.O2 import d.O2
import d.E import d.Outer
import d.ClassObject import d.T
import d.c
import d.ext
import d.g
fun f(a: A, t: T) { fun f(a: A, t: T) {
g(A(c).ext()) g(A(c).ext())
@@ -1,7 +1,7 @@
package to package to
import a.invoke
import a.A import a.A
import a.invoke
fun f(a: A) { fun f(a: A) {
a() a()
@@ -1,7 +1,7 @@
package to package to
import a.JavaM
import a.JavaF import a.JavaF
import a.JavaM
fun f() { fun f() {
JavaM.staticMethod() JavaM.staticMethod()
@@ -1,8 +1,8 @@
package to package to
import a.A
import a.component1 import a.component1
import a.component2 import a.component2
import a.A
fun f() { fun f() {
val (a, b) = A() val (a, b) = A()
@@ -1,9 +1,9 @@
package to package to
import a.next
import a.hasNext
import a.A import a.A
import a.B import a.B
import a.hasNext
import a.next
fun A.iterator() = B() fun A.iterator() = B()
@@ -1,6 +1,6 @@
package to package to
import a.d
import a.b import a.b
import a.d
fun f(c: IntRange) = d + b fun f(c: IntRange) = d + b
@@ -1,8 +1,8 @@
package to package to
import a.T
import a.A import a.A
import a.B import a.B
import a.T
fun g(t: T) { fun g(t: T) {
g(A) g(A)
@@ -1,6 +1,6 @@
package to package to
import a.c
import a.b import a.b
import a.c
fun f() = c + b fun f() = c + b
@@ -1,7 +1,7 @@
// "Change function signature to 'fun f(a: A)'" "true" // "Change function signature to 'fun f(a: A)'" "true"
// ERROR: 'f' overrides nothing // ERROR: 'f' overrides nothing
import a.B
import a.A import a.A
import a.B
class BB : B() { class BB : B() {
<caret>override fun f(a: A) {} <caret>override fun f(a: A) {}
@@ -1,8 +1,7 @@
// "Change function signature to 'fun f(a: A)'" "true" // "Change function signature to 'fun f(a: A)'" "true"
// ERROR: 'f' overrides nothing // ERROR: 'f' overrides nothing
import a.B
import a.A import a.A
import a.B
class A {} class A {}
class BB : B() { class BB : B() {
override fun f(a: A) {} override fun f(a: A) {}
@@ -1,7 +1,7 @@
// "Change type from 'String' to '(ModuleBuilder) -> Module'" "true" // "Change type from 'String' to '(ModuleBuilder) -> Module'" "true"
import kotlin.modules.ModuleBuilder
import kotlin.modules.Module import kotlin.modules.Module
import kotlin.modules.ModuleBuilder
fun foo(f: ((kotlin.modules.ModuleBuilder) -> kotlin.modules.Module) -> String) { fun foo(f: ((kotlin.modules.ModuleBuilder) -> kotlin.modules.Module) -> String) {
foo { foo {
@@ -1,8 +1,8 @@
package a package a
import b.test
import b.TEST import b.TEST
import b.Test import b.Test
import b.test
fun bar() { fun bar() {
val t: Test = Test() val t: Test = Test()
@@ -1,8 +1,8 @@
package a package a
import b.test
import b.TEST import b.TEST
import b.Test import b.Test
import b.test
fun bar() { fun bar() {
val t: Test = Test() val t: Test = Test()
@@ -1,8 +1,8 @@
package c package c
import b.TEST
import b.Test import b.Test
import b.test import b.test
import b.TEST
fun bar() { fun bar() {
val t: Test = Test() val t: Test = Test()
@@ -1,9 +1,9 @@
package c package c
import a.* import a.*
import b.test
import b.TEST import b.TEST
import b.Test import b.Test
import b.test
fun bar() { fun bar() {
val t: Test = Test() val t: Test = Test()
@@ -1,7 +1,7 @@
package target package target
import library.bar
import library.B import library.B
import library.bar
public class A: B() { public class A: B() {
fun test() { fun test() {
@@ -1,9 +1,9 @@
package first package first
import fourth.X
import second.A import second.A
import third.B import third.B
import third.D import third.D
import fourth.X
class Test { class Test {
val a = A() val a = A()
@@ -1,9 +1,9 @@
package first package first
import fourth.X
import second.A import second.A
import third.B import third.B
import third.D import third.D
import fourth.X
fun test() { fun test() {
val a = A() val a = A()
@@ -1,8 +1,8 @@
package target package target
import library.JavaClass import library.JavaClass
import library.KtObject
import library.KtClass import library.KtClass
import library.KtObject
class Foo { class Foo {
val jv1 = JavaClass.foo() val jv1 = JavaClass.foo()
@@ -1,8 +1,8 @@
package target package target
import library.JavaEnum import library.JavaEnum
import library.KtEnum
import library.KtData import library.KtData
import library.KtEnum
class Foo { class Foo {
val javaEnum = JavaEnum.values() val javaEnum = JavaEnum.values()
@@ -1,4 +1,4 @@
import java.util.Date
import java.sql import java.sql
import java.util.Date
val x = sql.Date(1) val x = sql.Date(1)
@@ -1,5 +1,5 @@
import p.globalVal
import p.globalFun import p.globalFun
import p.globalVal
fun foo() { fun foo() {
globalFun(globalVal) globalFun(globalVal)
@@ -1,6 +1,6 @@
import java.awt.Container
import java.io.File import java.io.File
import java.util.ArrayList import java.util.ArrayList
import java.awt.Container
class A { class A {
var x: ((File, ArrayList<String>) -> Container)? = null var x: ((File, ArrayList<String>) -> Container)? = null
@@ -1,4 +1,4 @@
import java.util.Date
import java.sql import java.sql
import java.util.Date
class A : sql.Date class A : sql.Date
@@ -1,4 +1,4 @@
import java.util.*
import java.sql.Date import java.sql.Date
import java.util.*
val v: ArrayList<Date> val v: ArrayList<Date>
@@ -1,6 +1,6 @@
import java.sql
import java.util.Date import java.util.Date
import java.util.HashMap import java.util.HashMap
import java.sql
class A { class A {
val x: HashMap<Date, sql.Date> val x: HashMap<Date, sql.Date>
@@ -221,4 +221,10 @@ public class AddImportTestGenerated extends AbstractAddImportTest {
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/PropertyAlreadyImported2.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/PropertyAlreadyImported2.kt");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("StdlibImportsLast.kt")
public void testStdlibImportsLast() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/StdlibImportsLast.kt");
doTest(fileName);
}
} }