Import insertion algorithm
This commit is contained in:
@@ -141,6 +141,7 @@ import org.jetbrains.kotlin.idea.decompiler.stubBuilder.AbstractClsStubBuilderTe
|
||||
import org.jetbrains.kotlin.codegen.AbstractLineNumberTest
|
||||
import org.jetbrains.kotlin.completion.handlers.AbstractKeywordCompletionHandlerTest
|
||||
import org.jetbrains.kotlin.idea.kdoc.AbstractKDocHighlightingTest
|
||||
import org.jetbrains.kotlin.addImport.AbstractAddImportTest
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
System.setProperty("java.awt.headless", "true")
|
||||
@@ -595,6 +596,9 @@ fun main(args: Array<String>) {
|
||||
testClass(javaClass<AbstractShortenRefsTest>()) {
|
||||
model("shortenRefs", pattern = """^([^\.]+)\.kt$""")
|
||||
}
|
||||
testClass(javaClass<AbstractAddImportTest>()) {
|
||||
model("addImport", pattern = """^([^\.]+)\.kt$""")
|
||||
}
|
||||
|
||||
testClass(javaClass<AbstractCompiledKotlinInJavaCompletionTest>()) {
|
||||
model("completion/injava", extension = "java")
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.psi.JetDeclaration
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
|
||||
private val LOG = Logger.getInstance(javaClass<KotlinCacheService>())
|
||||
|
||||
@@ -66,6 +67,10 @@ public class KotlinCacheService(val project: Project) {
|
||||
return cache.getAnalysisResultsForElements(elements)
|
||||
}
|
||||
|
||||
override fun getFileTopLevelScope(file: JetFile): JetScope {
|
||||
return getLazyResolveSession(file).getScopeProvider().getFileScope(file)
|
||||
}
|
||||
|
||||
override fun <T> get(extension: CacheExtension<T>): T {
|
||||
return cache[extension]
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.psi.JetDeclaration
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
|
||||
public trait ResolutionFacade {
|
||||
|
||||
@@ -32,6 +34,8 @@ public trait ResolutionFacade {
|
||||
|
||||
public fun resolveToDescriptor(declaration: JetDeclaration): DeclarationDescriptor
|
||||
|
||||
public fun getFileTopLevelScope(file: JetFile): JetScope
|
||||
|
||||
public fun findModuleDescriptor(element: JetElement): ModuleDescriptor
|
||||
|
||||
public fun <T> get(extension: CacheExtension<T>): T
|
||||
|
||||
@@ -27,16 +27,15 @@ import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import java.util.Collections
|
||||
import org.jetbrains.kotlin.analyzer.analyzeInContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
||||
import java.util.LinkedHashSet
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
|
||||
public object ShortenReferences {
|
||||
public fun process(element: JetElement) {
|
||||
@@ -303,17 +302,9 @@ public object ShortenReferences {
|
||||
private var optimizeImports = true
|
||||
|
||||
fun addImport(target: DeclarationDescriptor): Boolean {
|
||||
val realTarget = if (DescriptorUtils.isClassObject(target)) // references to class object are treated as ones to its owner class
|
||||
target.getContainingDeclaration() as? ClassDescriptor ?: return false
|
||||
else
|
||||
target
|
||||
|
||||
if (realTarget !is ClassDescriptor && realTarget !is PackageViewDescriptor) return false
|
||||
if (realTarget.getContainingDeclaration() is ClassDescriptor) return false // do not insert imports for nested classes
|
||||
|
||||
if (target !is ClassDescriptor && target !is PackageViewDescriptor) return false
|
||||
optimizeImports()
|
||||
ImportInsertHelper.INSTANCE.writeImportToFile(ImportPath(DescriptorUtils.getFqNameSafe(realTarget), false), file)
|
||||
return true
|
||||
return ImportInsertHelper.INSTANCE.importDescriptor(file, target)
|
||||
}
|
||||
|
||||
fun optimizeImports(): Boolean {
|
||||
|
||||
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetImportDirective
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||
|
||||
public trait ImportInsertHelper {
|
||||
|
||||
@@ -34,7 +36,13 @@ public trait ImportInsertHelper {
|
||||
|
||||
public fun needImport(importPath: ImportPath, file: JetFile, importDirectives: List<JetImportDirective> = file.getImportDirectives()): Boolean
|
||||
|
||||
public fun writeImportToFile(importPath: ImportPath, file: JetFile)
|
||||
public fun writeImportToFile(importPath: ImportPath, file: JetFile): JetImportDirective
|
||||
|
||||
/**
|
||||
* Returns true, if the descriptor is imported (even if no import was added because it's not needed)
|
||||
* and false, if importing of this descriptor is either impossible or not allowed by code style.
|
||||
*/
|
||||
public fun importDescriptor(file: JetFile, descriptor: DeclarationDescriptor): Boolean
|
||||
|
||||
class object {
|
||||
public val INSTANCE: ImportInsertHelper
|
||||
|
||||
@@ -41,6 +41,8 @@ public class JetCodeStyleSettings extends CustomCodeStyleSettings {
|
||||
|
||||
public boolean LBRACE_ON_NEXT_LINE = false;
|
||||
|
||||
public boolean PREFER_ALL_UNDER_IMPORTS = false;
|
||||
|
||||
public static JetCodeStyleSettings getInstance(Project project) {
|
||||
return CodeStyleSettingsManager.getSettings(project).getCustomSettings(JetCodeStyleSettings.class);
|
||||
}
|
||||
|
||||
@@ -20,11 +20,32 @@ import com.intellij.codeInsight.CodeInsightSettings
|
||||
import com.intellij.codeInsight.actions.OptimizeImportsProcessor
|
||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
||||
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.formatter.JetCodeStyleSettings
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import java.util.LinkedHashSet
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqNameSafe
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
|
||||
public class ImportInsertHelperImpl : ImportInsertHelper {
|
||||
/**
|
||||
@@ -53,28 +74,29 @@ public class ImportInsertHelperImpl : ImportInsertHelper {
|
||||
}
|
||||
}
|
||||
|
||||
override fun writeImportToFile(importPath: ImportPath, file: JetFile) {
|
||||
override fun writeImportToFile(importPath: ImportPath, file: JetFile): JetImportDirective {
|
||||
val psiFactory = JetPsiFactory(file.getProject())
|
||||
if (file is JetCodeFragment) {
|
||||
val newDirective = psiFactory.createImportDirective(importPath)
|
||||
file.addImportsFromString(newDirective.getText())
|
||||
return
|
||||
return newDirective
|
||||
}
|
||||
|
||||
val importList = file.getImportList()
|
||||
if (importList != null) {
|
||||
val newDirective = psiFactory.createImportDirective(importPath)
|
||||
importList.add(psiFactory.createNewLine())
|
||||
importList.add(newDirective)
|
||||
return importList.add(newDirective) as JetImportDirective
|
||||
}
|
||||
else {
|
||||
val newDirective = psiFactory.createImportDirectiveWithImportList(importPath)
|
||||
val newImportList = psiFactory.createImportDirectiveWithImportList(importPath)
|
||||
val packageDirective = file.getPackageDirective()
|
||||
if (packageDirective == null) {
|
||||
throw IllegalStateException("Scripts are not supported: " + file.getName())
|
||||
}
|
||||
|
||||
packageDirective.getParent().addAfter(newDirective, packageDirective)
|
||||
val addedImportList = packageDirective.getParent().addAfter(newImportList, packageDirective) as JetImportList
|
||||
return addedImportList.getImports().single()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,4 +148,220 @@ public class ImportInsertHelperImpl : ImportInsertHelper {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun importDescriptor(file: JetFile, descriptor: DeclarationDescriptor): Boolean {
|
||||
return Importer(file).importDescriptor(descriptor)
|
||||
}
|
||||
|
||||
private inner class Importer(
|
||||
private val file: JetFile
|
||||
) {
|
||||
private val resolutionFacade = file.getResolutionFacade()
|
||||
private val preferAllUnderImports = JetCodeStyleSettings.getInstance(file.getProject()).PREFER_ALL_UNDER_IMPORTS
|
||||
|
||||
fun importDescriptor(descriptor: DeclarationDescriptor): Boolean {
|
||||
val target = if (DescriptorUtils.isClassObject(descriptor)) // references to class object are treated as ones to its owner class
|
||||
descriptor.getContainingDeclaration() as? ClassDescriptor ?: return false
|
||||
else
|
||||
descriptor
|
||||
|
||||
val name = target.getName()
|
||||
val topLevelScope = resolutionFacade.getFileTopLevelScope(file)
|
||||
|
||||
// check if import is not needed
|
||||
when (target) {
|
||||
is ClassDescriptor -> { if (topLevelScope.getClassifier(name) == target) return true }
|
||||
is PackageViewDescriptor -> { if (topLevelScope.getPackage(name) == target) return true }
|
||||
is FunctionDescriptor -> { if (topLevelScope.getFunctions(name).contains(target)) return true }
|
||||
is PropertyDescriptor -> { if (topLevelScope.getProperties(name).contains(target)) return true }
|
||||
else -> return false
|
||||
}
|
||||
|
||||
// do not insert imports for non-top level declarations
|
||||
if (target !is PackageViewDescriptor && target.getContainingDeclaration() !is PackageFragmentDescriptor) return false
|
||||
|
||||
val imports = file.getImportDirectives()
|
||||
|
||||
//TODO: is that correct? What if function is imported and we need to import class?
|
||||
if (imports.any { it.getImportedName() == name.asString() }) return false
|
||||
|
||||
val fqName = target.importableFqNameSafe
|
||||
val packageFqName = fqName.parent()
|
||||
|
||||
val allUnderImportPath = ImportPath(packageFqName, true)
|
||||
val tryAllUnderImport = preferAllUnderImports
|
||||
&& !packageFqName.isRoot()
|
||||
&& !imports.any { it.getImportPath() == allUnderImportPath }
|
||||
&& when (target) {
|
||||
is ClassDescriptor -> topLevelScope.getClassifier(name) == null // this check does not give a guarantee that import with * will import the class - for example, there can be classes with conflicting name in more than one import with *
|
||||
is PackageViewDescriptor -> false
|
||||
is FunctionDescriptor, is PropertyDescriptor -> true
|
||||
else -> throw Exception()
|
||||
}
|
||||
|
||||
if (tryAllUnderImport && addAllUnderImport(target)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return addExplicitImport(target)
|
||||
}
|
||||
|
||||
private fun addAllUnderImport(target: DeclarationDescriptor): Boolean {
|
||||
val targetFqName = target.importableFqNameSafe
|
||||
val parentFqName = targetFqName.parent()
|
||||
|
||||
val moduleDescriptor = resolutionFacade.findModuleDescriptor(file)
|
||||
val imports = file.getImportDirectives()
|
||||
val scopeToImport = getMemberScope(parentFqName, moduleDescriptor) ?: return false
|
||||
val importedScopes = imports
|
||||
.filter { it.isAllUnder () }
|
||||
.map {
|
||||
val importPath = it.getImportPath()
|
||||
if (importPath != null) {
|
||||
val fqName = importPath.fqnPart()
|
||||
getMemberScope(fqName, moduleDescriptor)
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
}
|
||||
.filterNotNull()
|
||||
|
||||
val classNamesToImport = scopeToImport
|
||||
.getDescriptorsFiltered(DescriptorKindFilter.CLASSIFIERS, { true })
|
||||
.map { it.getName() }
|
||||
|
||||
val aliasNames = imports.map { it.getImportedName() }.filterNotNull().toSet()
|
||||
//TODO: check for visibility
|
||||
var conflictCandidates: List<ClassifierDescriptor> = classNamesToImport
|
||||
.filter { it.asString() !in aliasNames }
|
||||
.flatMap {
|
||||
importedScopes.map { scope -> scope.getClassifier(it) }.filterNotNull()
|
||||
}
|
||||
val conflicts = detectNeededImports(conflictCandidates)
|
||||
|
||||
val addedImport = addImport(parentFqName, true)
|
||||
|
||||
if (target is ClassDescriptor) {
|
||||
val newTopLevelScope = resolutionFacade.getFileTopLevelScope(file)
|
||||
val resolvedTo = newTopLevelScope.getClassifier(target.getName())
|
||||
if (resolvedTo?.importableFqNameSafe != targetFqName) {
|
||||
addedImport.delete()
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for (conflict in conflicts) {
|
||||
addImport(DescriptorUtils.getFqNameSafe(conflict), false)
|
||||
}
|
||||
|
||||
dropRedundantExplicitImports(parentFqName)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getMemberScope(fqName: FqName, moduleDescriptor: ModuleDescriptor): JetScope? {
|
||||
val packageView = moduleDescriptor.getPackage(fqName)
|
||||
if (packageView != null) {
|
||||
return packageView.getMemberScope()
|
||||
}
|
||||
|
||||
val parentScope = getMemberScope(fqName.parent(), moduleDescriptor) ?: return null
|
||||
val classDescriptor = parentScope.getClassifier(fqName.shortName()) as? ClassDescriptor ?: return null
|
||||
return classDescriptor.getDefaultType().getMemberScope()
|
||||
}
|
||||
|
||||
private fun addExplicitImport(target: DeclarationDescriptor): Boolean {
|
||||
if (target is ClassDescriptor || target is PackageViewDescriptor) {
|
||||
val topLevelScope = resolutionFacade.getFileTopLevelScope(file)
|
||||
val name = target.getName()
|
||||
|
||||
val classifier = topLevelScope.getClassifier(name)
|
||||
if (classifier != null && detectNeededImports(listOf(classifier)).isNotEmpty()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
addImport(target.importableFqNameSafe, false)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun dropRedundantExplicitImports(packageFqName: FqName) {
|
||||
val dropCandidates = file.getImportDirectives().filter {
|
||||
!it.isAllUnder() && it.getAliasName() == null && it.getImportPath()?.fqnPart()?.parent() == packageFqName
|
||||
}
|
||||
|
||||
val importsToCheck = ArrayList<FqName>()
|
||||
for (import in dropCandidates) {
|
||||
val importedReference = import.getImportedReference() ?: continue
|
||||
val refExpr = (importedReference as JetDotQualifiedExpression).getSelectorExpression() as JetSimpleNameExpression
|
||||
val targets = refExpr.resolveTargets()
|
||||
if (targets.any { it is PackageViewDescriptor }) continue // do not drop import of package
|
||||
val classDescriptor = targets.filterIsInstance<ClassDescriptor>().firstOrNull()
|
||||
importsToCheck.addIfNotNull(classDescriptor?.importableFqNameSafe)
|
||||
import.delete()
|
||||
}
|
||||
|
||||
if (importsToCheck.isNotEmpty()) {
|
||||
val topLevelScope = resolutionFacade.getFileTopLevelScope(file)
|
||||
for (classFqName in importsToCheck) {
|
||||
if (topLevelScope.getClassifier(classFqName.shortName())?.importableFqNameSafe != classFqName) {
|
||||
addImport(classFqName, false) // restore explicit import
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun detectNeededImports(importedDescriptors: Collection<DeclarationDescriptor>): Set<DeclarationDescriptor> {
|
||||
if (importedDescriptors.isEmpty()) return setOf()
|
||||
|
||||
val descriptorsToCheck = importedDescriptors.map { it.getName() to it }.toMap().toLinkedMap()
|
||||
val result = LinkedHashSet<DeclarationDescriptor>()
|
||||
file.accept(object : JetVisitorVoid() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
if (descriptorsToCheck.isEmpty()) return
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
|
||||
override fun visitImportList(importList: JetImportList) {
|
||||
}
|
||||
|
||||
override fun visitPackageDirective(directive: JetPackageDirective) {
|
||||
}
|
||||
|
||||
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) {
|
||||
if (JetPsiUtil.isSelectorInQualified(expression)) return
|
||||
|
||||
val refName = expression.getReferencedNameAsName()
|
||||
val descriptor = descriptorsToCheck[refName]
|
||||
if (descriptor != null) {
|
||||
val targetFqName = targetFqName(expression)
|
||||
if (targetFqName != null && targetFqName == DescriptorUtils.getFqNameSafe(descriptor)) {
|
||||
descriptorsToCheck.remove(refName)
|
||||
result.add(descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
private fun JetImportDirective.getImportedName(): String? = JetPsiUtil.getAliasName(this)?.getIdentifier()
|
||||
|
||||
private fun targetFqName(ref: JetReferenceExpression): FqName? {
|
||||
return ref.resolveTargets().map { it.importableFqName }.toSet().singleOrNull()
|
||||
|
||||
}
|
||||
|
||||
private fun JetReferenceExpression.resolveTargets(): Collection<DeclarationDescriptor> {
|
||||
val bindingContext = resolutionFacade.analyze(this, BodyResolveMode.PARTIAL)
|
||||
return bindingContext[BindingContext.REFERENCE_TARGET, this]?.let { listOf(it) }
|
||||
?: bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, this]
|
||||
?: return listOf()
|
||||
}
|
||||
|
||||
private fun addImport(fqName: FqName, allUnder: Boolean): JetImportDirective {
|
||||
return writeImportToFile(ImportPath(fqName, allUnder), file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: class: kotlin.String
|
||||
package p
|
||||
|
||||
import java.lang.String
|
||||
|
||||
fun foo(): ArrayList<String> {}
|
||||
@@ -0,0 +1 @@
|
||||
Failed to add import
|
||||
@@ -0,0 +1,4 @@
|
||||
// IMPORT: java.sql.Date
|
||||
import java.util.*
|
||||
|
||||
val d: Date = Date()
|
||||
@@ -0,0 +1 @@
|
||||
Failed to add import
|
||||
@@ -0,0 +1,4 @@
|
||||
// IMPORT: java.sql.Date
|
||||
import java.util as Date
|
||||
|
||||
val d: Date.Date = Date.Date()
|
||||
@@ -0,0 +1 @@
|
||||
Failed to add import
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.util.*
|
||||
|
||||
fun foo(): ArrayList<String> {}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.util.*
|
||||
|
||||
fun foo(): ArrayList<String> {}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
fun foo(): ArrayList<String> {}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
fun foo(): ArrayList<String> {}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
|
||||
val d = Date()
|
||||
@@ -0,0 +1,8 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
import java.util.*
|
||||
import java.sql.Date
|
||||
|
||||
val d = Date()
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
|
||||
val d: Date? = null
|
||||
@@ -0,0 +1,8 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
import java.util.*
|
||||
import java.sql.Date
|
||||
|
||||
val d: Date? = null
|
||||
@@ -0,0 +1,5 @@
|
||||
package dependency
|
||||
|
||||
class Date
|
||||
|
||||
fun Date(s: String) = Date()
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import dependency.*
|
||||
|
||||
val d = Date(1, 2)
|
||||
@@ -0,0 +1,8 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import dependency.*
|
||||
import java.util.*
|
||||
import dependency.Date
|
||||
|
||||
val d = Date(1, 2)
|
||||
@@ -0,0 +1,7 @@
|
||||
package dependency
|
||||
|
||||
class Date {
|
||||
class object {
|
||||
val VALUE = 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import dependency.*
|
||||
|
||||
val d = Date.VALUE
|
||||
@@ -0,0 +1,8 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import dependency.*
|
||||
import java.util.*
|
||||
import dependency.Date
|
||||
|
||||
val d = Date.VALUE
|
||||
@@ -0,0 +1,5 @@
|
||||
package dependency
|
||||
|
||||
class AClass {
|
||||
class Date
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import dependency.AClass.*
|
||||
|
||||
val d = Date()
|
||||
@@ -0,0 +1,8 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import dependency.AClass.*
|
||||
import java.util.*
|
||||
import dependency.AClass.Date
|
||||
|
||||
val d = Date()
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
|
||||
val d: java.sql.Date? = null
|
||||
@@ -0,0 +1,7 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
import java.util.*
|
||||
|
||||
val d: java.sql.Date? = null
|
||||
@@ -0,0 +1,8 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
|
||||
class Date
|
||||
|
||||
val d: Date? = null
|
||||
@@ -0,0 +1,9 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
import java.util.*
|
||||
|
||||
class Date
|
||||
|
||||
val d: Date? = null
|
||||
@@ -0,0 +1,3 @@
|
||||
package dependency
|
||||
|
||||
class Date
|
||||
@@ -0,0 +1,7 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import dependency.*
|
||||
import java.sql.*
|
||||
|
||||
val d = Date()
|
||||
@@ -0,0 +1,8 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import dependency.*
|
||||
import java.sql.*
|
||||
import java.util.*
|
||||
|
||||
val d = Date()
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
|
||||
val d: Driver? = null
|
||||
@@ -0,0 +1,7 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
import java.util.*
|
||||
|
||||
val d: Driver? = null
|
||||
@@ -0,0 +1,7 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
import java.sql.Date
|
||||
|
||||
val d: Date? = null
|
||||
@@ -0,0 +1,8 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
import java.sql.Date
|
||||
import java.util.*
|
||||
|
||||
val d: Date? = null
|
||||
@@ -0,0 +1,4 @@
|
||||
// IMPORT: java.sql.Date
|
||||
package p
|
||||
|
||||
import java.util.*
|
||||
@@ -0,0 +1,5 @@
|
||||
// IMPORT: java.sql.Date
|
||||
package p
|
||||
|
||||
import java.util.*
|
||||
import java.sql.Date
|
||||
@@ -0,0 +1,5 @@
|
||||
// IMPORT: java.sql.Date
|
||||
package p
|
||||
|
||||
import java.util.*
|
||||
import java.sql.*
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.sql.Date
|
||||
package p
|
||||
|
||||
import java.util.*
|
||||
import java.sql.*
|
||||
import java.sql.Date
|
||||
@@ -0,0 +1,3 @@
|
||||
package dependency
|
||||
|
||||
class Date
|
||||
@@ -0,0 +1,5 @@
|
||||
// IMPORT: dependency.Date
|
||||
package p
|
||||
|
||||
import java.util.*
|
||||
import java.sql.*
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: dependency.Date
|
||||
package p
|
||||
|
||||
import java.util.*
|
||||
import java.sql.*
|
||||
import dependency.Date
|
||||
@@ -0,0 +1,14 @@
|
||||
// IMPORT: java.util.HashMap
|
||||
package p
|
||||
|
||||
import java.sql.*
|
||||
import java.util.ArrayList // maybe dropped on adding import with *
|
||||
import java.util.Date // should not be dropped because of conflicting java.sql.Date class
|
||||
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() {
|
||||
val v1 = JavaHashSet()
|
||||
val v2 = Date()
|
||||
val v3 = ArrayList()
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// IMPORT: java.util.HashMap
|
||||
package p
|
||||
|
||||
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.Date
|
||||
|
||||
fun foo() {
|
||||
val v1 = JavaHashSet()
|
||||
val v2 = Date()
|
||||
val v3 = ArrayList()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package dependency
|
||||
|
||||
fun function(){}
|
||||
val property: Int = 0
|
||||
class Class1
|
||||
class Class2
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: dependency.Class2
|
||||
package p
|
||||
|
||||
import dependency.Class1
|
||||
import dependency.function
|
||||
import dependency.property
|
||||
@@ -0,0 +1,4 @@
|
||||
// IMPORT: dependency.Class2
|
||||
package p
|
||||
|
||||
import dependency.*
|
||||
@@ -0,0 +1,3 @@
|
||||
package dependency
|
||||
|
||||
fun foo(){}
|
||||
@@ -0,0 +1,8 @@
|
||||
// IMPORT: dependency.foo
|
||||
package p
|
||||
|
||||
import dependency.foo
|
||||
|
||||
fun f() {
|
||||
foo()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// IMPORT: dependency.foo
|
||||
package p
|
||||
|
||||
import dependency.foo
|
||||
|
||||
fun f() {
|
||||
foo()
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package dependency
|
||||
|
||||
fun foo(){}
|
||||
@@ -0,0 +1,8 @@
|
||||
// IMPORT: dependency.foo
|
||||
package p
|
||||
|
||||
import dependency.*
|
||||
|
||||
fun f() {
|
||||
foo()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// IMPORT: dependency.foo
|
||||
package p
|
||||
|
||||
import dependency.*
|
||||
|
||||
fun f() {
|
||||
foo()
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
fun foo() {}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util.ArrayList
|
||||
package p
|
||||
|
||||
import java.util.*
|
||||
|
||||
fun foo() {}
|
||||
@@ -0,0 +1,4 @@
|
||||
// IMPORT: java.util
|
||||
package p
|
||||
|
||||
fun foo(): util.ArrayList<String> {}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util
|
||||
package p
|
||||
|
||||
import java.util
|
||||
|
||||
fun foo(): util.ArrayList<String> {}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: class: kotlin.String
|
||||
package p
|
||||
|
||||
import java.util.*
|
||||
|
||||
fun foo(): ArrayList<String> {}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: class: kotlin.String
|
||||
package p
|
||||
|
||||
import java.util.*
|
||||
|
||||
fun foo(): ArrayList<String> {}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util
|
||||
package p
|
||||
|
||||
import java.util
|
||||
|
||||
fun foo(): util.ArrayList<String> {}
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: java.util
|
||||
package p
|
||||
|
||||
import java.util
|
||||
|
||||
fun foo(): util.ArrayList<String> {}
|
||||
@@ -0,0 +1,3 @@
|
||||
package dependency
|
||||
|
||||
val foo: Int = 1
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: dependency.foo
|
||||
package p
|
||||
|
||||
import dependency.foo
|
||||
|
||||
fun f() = foo
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: dependency.foo
|
||||
package p
|
||||
|
||||
import dependency.foo
|
||||
|
||||
fun f() = foo
|
||||
@@ -0,0 +1,3 @@
|
||||
package dependency
|
||||
|
||||
val foo: Int = 1
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: dependency.foo
|
||||
package p
|
||||
|
||||
import dependency.*
|
||||
|
||||
fun f() = foo
|
||||
@@ -0,0 +1,6 @@
|
||||
// IMPORT: dependency.foo
|
||||
package p
|
||||
|
||||
import dependency.*
|
||||
|
||||
fun f() = foo
|
||||
@@ -1,4 +1,4 @@
|
||||
// OPTIMIZE_IMPORTS
|
||||
// OPTIMIZE_IMPORTS: true
|
||||
import java.util.Date
|
||||
|
||||
val x = <selection>java.sql.Date(1)</selection>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// OPTIMIZE_IMPORTS
|
||||
// OPTIMIZE_IMPORTS: true
|
||||
import java.sql.Date
|
||||
|
||||
val x = Date(1)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// OPTIMIZE_IMPORTS
|
||||
// OPTIMIZE_IMPORTS: true
|
||||
import java.util.Date
|
||||
|
||||
class A : <selection>java.sql.Date</selection>
|
||||
@@ -1,4 +1,4 @@
|
||||
// OPTIMIZE_IMPORTS
|
||||
// OPTIMIZE_IMPORTS: true
|
||||
import java.sql.Date
|
||||
|
||||
class A : Date
|
||||
@@ -1,4 +1,4 @@
|
||||
// OPTIMIZE_IMPORTS
|
||||
// OPTIMIZE_IMPORTS: true
|
||||
import java.io.*
|
||||
|
||||
<selection>class A(val d: java.sql.Date, val rs: java.sql.ResultSet)</selection>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// OPTIMIZE_IMPORTS
|
||||
// OPTIMIZE_IMPORTS: true
|
||||
import java.sql.Date
|
||||
import java.sql.ResultSet
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.idea.JetLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.test.JetTestUtils
|
||||
import org.jetbrains.kotlin.idea.JetWithJdkAndRuntimeLightProjectDescriptor
|
||||
import com.intellij.codeInsight.CodeInsightSettings
|
||||
import org.jetbrains.kotlin.idea.formatter.JetCodeStyleSettings
|
||||
import java.io.File
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import com.intellij.openapi.command.CommandProcessor
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import org.jetbrains.kotlin.idea.codeInsight.ShortenReferences
|
||||
|
||||
public abstract class AbstractImportsTest : JetLightCodeInsightFixtureTestCase() {
|
||||
override fun getTestDataPath() = JetTestUtils.getHomeDirectory()
|
||||
override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
||||
|
||||
protected fun doTest(testPath: String) {
|
||||
val codeInsightSettings = CodeInsightSettings.getInstance()
|
||||
val codeStyleSettings = JetCodeStyleSettings.getInstance(getProject())
|
||||
val optimizeImportsBefore = codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY
|
||||
val preferAllUnderBefore = codeStyleSettings.PREFER_ALL_UNDER_IMPORTS
|
||||
|
||||
try {
|
||||
val fixture = myFixture
|
||||
val dependencyPath = testPath.replace(".kt", ".dependency.kt")
|
||||
if (File(dependencyPath).exists()) {
|
||||
fixture.configureByFile(dependencyPath)
|
||||
}
|
||||
val javaDependencyPath = testPath.replace(".kt", ".dependency.java")
|
||||
if (File(javaDependencyPath).exists()) {
|
||||
fixture.configureByFile(javaDependencyPath)
|
||||
}
|
||||
|
||||
fixture.configureByFile(testPath)
|
||||
|
||||
val file = fixture.getFile() as JetFile
|
||||
|
||||
codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY = InTextDirectivesUtils.getPrefixedBoolean(file.getText(), "// OPTIMIZE_IMPORTS:") ?: false
|
||||
codeStyleSettings.PREFER_ALL_UNDER_IMPORTS = InTextDirectivesUtils.getPrefixedBoolean(file.getText(), "// ALL_UNDER_IMPORTS:") ?: preferAllUnderImportsDefault
|
||||
|
||||
CommandProcessor.getInstance().executeCommand(getProject(), {
|
||||
ApplicationManager.getApplication()!!.runWriteAction {
|
||||
doTest(file)
|
||||
}
|
||||
}, null, null)
|
||||
|
||||
fixture.checkResultByFile(testPath + ".after")
|
||||
}
|
||||
finally {
|
||||
codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY = optimizeImportsBefore
|
||||
codeStyleSettings.PREFER_ALL_UNDER_IMPORTS = preferAllUnderBefore
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun doTest(file: JetFile)
|
||||
|
||||
protected open val preferAllUnderImportsDefault: Boolean
|
||||
get() = true
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.addImport
|
||||
|
||||
import org.jetbrains.kotlin.AbstractImportsTest
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.quickfix.ImportInsertHelper
|
||||
import org.jetbrains.kotlin.psi.JetPsiFactory
|
||||
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver
|
||||
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver.LookupMode
|
||||
import org.jetbrains.kotlin.resolve.JetModuleUtil
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceContext
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
|
||||
public abstract class AbstractAddImportTest : AbstractImportsTest() {
|
||||
override fun doTest(file: JetFile) {
|
||||
var descriptorName = InTextDirectivesUtils.findStringWithPrefixes(file.getText(), "// IMPORT:")
|
||||
?: error("No IMPORT directive defined")
|
||||
|
||||
var filter: (DeclarationDescriptor) -> Boolean = { true }
|
||||
if (descriptorName.startsWith("class:")) {
|
||||
filter = { it is ClassDescriptor }
|
||||
descriptorName = descriptorName.substring("class:".length()).trim()
|
||||
}
|
||||
|
||||
val importDirective = JetPsiFactory(getProject()).createImportDirective(descriptorName)
|
||||
val moduleDescriptor = file.getResolutionFacade().findModuleDescriptor(file)
|
||||
val scope = JetModuleUtil.getSubpackagesOfRootScope(moduleDescriptor)
|
||||
val descriptors = QualifiedExpressionResolver()
|
||||
.processImportReference(importDirective, scope, scope, null, BindingTraceContext(), LookupMode.EVERYTHING)
|
||||
.filter(filter)
|
||||
|
||||
when {
|
||||
descriptors.isEmpty() ->
|
||||
error("No descriptor $descriptorName found")
|
||||
|
||||
descriptors.size() > 1 ->
|
||||
error("Multiple descriptors found:\n " + descriptors.map { DescriptorRenderer.FQ_NAMES_IN_TYPES.render(it) }.joinToString("\n "))
|
||||
|
||||
else -> {
|
||||
val success = ImportInsertHelper.INSTANCE.importDescriptor(file, descriptors.single())
|
||||
if (!success) {
|
||||
val document = PsiDocumentManager.getInstance(getProject()).getDocument(file)
|
||||
document.replaceString(0, document.getTextLength(), "Failed to add import")
|
||||
PsiDocumentManager.getInstance(getProject()).commitAllDocuments()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.addImport;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.InnerTestClasses;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.JetTestUtils;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("idea/testData/addImport")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class AddImportTestGenerated extends AbstractAddImportTest {
|
||||
public void testAllFilesPresentInAddImport() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/addImport"), Pattern.compile("^([^\\.]+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("CannotImportClass1.kt")
|
||||
public void testCannotImportClass1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/CannotImportClass1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("CannotImportClass2.kt")
|
||||
public void testCannotImportClass2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/CannotImportClass2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("CannotImportClass3.kt")
|
||||
public void testCannotImportClass3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/CannotImportClass3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ClassAlreadyImported1.kt")
|
||||
public void testClassAlreadyImported1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ClassAlreadyImported1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ClassAlreadyImported2.kt")
|
||||
public void testClassAlreadyImported2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ClassAlreadyImported2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameAppearsAndHasUsage1.kt")
|
||||
public void testConflictingNameAppearsAndHasUsage1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsAndHasUsage1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameAppearsAndHasUsage2.kt")
|
||||
public void testConflictingNameAppearsAndHasUsage2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsAndHasUsage2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameAppearsAndHasUsage3.kt")
|
||||
public void testConflictingNameAppearsAndHasUsage3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsAndHasUsage3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameAppearsAndHasUsage4.kt")
|
||||
public void testConflictingNameAppearsAndHasUsage4() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsAndHasUsage4.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameAppearsAndHasUsage5.kt")
|
||||
public void testConflictingNameAppearsAndHasUsage5() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsAndHasUsage5.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameAppearsButUsageIsQualified.kt")
|
||||
public void testConflictingNameAppearsButUsageIsQualified() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsButUsageIsQualified.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameAppearsFalseUsage.kt")
|
||||
public void testConflictingNameAppearsFalseUsage() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsFalseUsage.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameAppearsFalseUsage2.kt")
|
||||
public void testConflictingNameAppearsFalseUsage2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsFalseUsage2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameAppearsNoUsage.kt")
|
||||
public void testConflictingNameAppearsNoUsage() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameAppearsNoUsage.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameHasExplicitImportAlready.kt")
|
||||
public void testConflictingNameHasExplicitImportAlready() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameHasExplicitImportAlready.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameNoAllUnderImport.kt")
|
||||
public void testConflictingNameNoAllUnderImport() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameNoAllUnderImport.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameNoAllUnderImport2.kt")
|
||||
public void testConflictingNameNoAllUnderImport2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameNoAllUnderImport2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ConflictingNameNoAllUnderImport3.kt")
|
||||
public void testConflictingNameNoAllUnderImport3() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ConflictingNameNoAllUnderImport3.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("DropExplicitImports.kt")
|
||||
public void testDropExplicitImports() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/DropExplicitImports.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("DropExplicitImports2.kt")
|
||||
public void testDropExplicitImports2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/DropExplicitImports2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("FunctionAlreadyImported1.kt")
|
||||
public void testFunctionAlreadyImported1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/FunctionAlreadyImported1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("FunctionAlreadyImported2.kt")
|
||||
public void testFunctionAlreadyImported2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/FunctionAlreadyImported2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ImportClassSimple.kt")
|
||||
public void testImportClassSimple() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ImportClassSimple.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("ImportPackage.kt")
|
||||
public void testImportPackage() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/ImportPackage.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("NoNeedToImportStandardClass.kt")
|
||||
public void testNoNeedToImportStandardClass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/NoNeedToImportStandardClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("PackageAlreadyImported.kt")
|
||||
public void testPackageAlreadyImported() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/PackageAlreadyImported.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("PropertyAlreadyImported1.kt")
|
||||
public void testPropertyAlreadyImported1() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/PropertyAlreadyImported1.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("PropertyAlreadyImported2.kt")
|
||||
public void testPropertyAlreadyImported2() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/addImport/PropertyAlreadyImported2.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
@@ -17,55 +17,17 @@
|
||||
package org.jetbrains.kotlin.shortenRefs
|
||||
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.idea.JetWithJdkAndRuntimeLightProjectDescriptor
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import java.io.File
|
||||
import com.intellij.openapi.command.CommandProcessor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.JetLightCodeInsightFixtureTestCase
|
||||
import com.intellij.codeInsight.CodeInsightSettings
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.JetTestUtils
|
||||
import org.jetbrains.kotlin.AbstractImportsTest
|
||||
|
||||
public abstract class AbstractShortenRefsTest : JetLightCodeInsightFixtureTestCase() {
|
||||
override fun getTestDataPath() = JetTestUtils.getHomeDirectory()
|
||||
override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
||||
|
||||
protected fun doTest(testPath: String) {
|
||||
val codeInsightSettings = CodeInsightSettings.getInstance()
|
||||
val optimizeImportsBefore = codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY
|
||||
|
||||
try {
|
||||
val fixture = myFixture
|
||||
val dependencyPath = testPath.replace(".kt", ".dependency.kt")
|
||||
if (File(dependencyPath).exists()) {
|
||||
fixture.configureByFile(dependencyPath)
|
||||
}
|
||||
val javaDependencyPath = testPath.replace(".kt", ".dependency.java")
|
||||
if (File(javaDependencyPath).exists()) {
|
||||
fixture.configureByFile(javaDependencyPath)
|
||||
}
|
||||
|
||||
fixture.configureByFile(testPath)
|
||||
|
||||
val file = fixture.getFile() as JetFile
|
||||
val selectionModel = fixture.getEditor().getSelectionModel()
|
||||
if (!selectionModel.hasSelection()) error("No selection in input file")
|
||||
|
||||
codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY =
|
||||
InTextDirectivesUtils.isDirectiveDefined(file.getText(), "// OPTIMIZE_IMPORTS")
|
||||
|
||||
CommandProcessor.getInstance().executeCommand(getProject(), {
|
||||
ApplicationManager.getApplication()!!.runWriteAction {
|
||||
ShortenReferences.process(file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd())
|
||||
}
|
||||
}, null, null)
|
||||
selectionModel.removeSelection()
|
||||
|
||||
fixture.checkResultByFile(testPath + ".after")
|
||||
}
|
||||
finally {
|
||||
codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY = optimizeImportsBefore
|
||||
}
|
||||
public abstract class AbstractShortenRefsTest : AbstractImportsTest() {
|
||||
override fun doTest(file: JetFile) {
|
||||
val selectionModel = myFixture.getEditor().getSelectionModel()
|
||||
if (!selectionModel.hasSelection()) error("No selection in input file")
|
||||
ShortenReferences.process(file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd())
|
||||
selectionModel.removeSelection()
|
||||
}
|
||||
|
||||
override val preferAllUnderImportsDefault: Boolean
|
||||
get() = false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user