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.codegen.AbstractLineNumberTest
|
||||||
import org.jetbrains.kotlin.completion.handlers.AbstractKeywordCompletionHandlerTest
|
import org.jetbrains.kotlin.completion.handlers.AbstractKeywordCompletionHandlerTest
|
||||||
import org.jetbrains.kotlin.idea.kdoc.AbstractKDocHighlightingTest
|
import org.jetbrains.kotlin.idea.kdoc.AbstractKDocHighlightingTest
|
||||||
|
import org.jetbrains.kotlin.addImport.AbstractAddImportTest
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
System.setProperty("java.awt.headless", "true")
|
System.setProperty("java.awt.headless", "true")
|
||||||
@@ -595,6 +596,9 @@ fun main(args: Array<String>) {
|
|||||||
testClass(javaClass<AbstractShortenRefsTest>()) {
|
testClass(javaClass<AbstractShortenRefsTest>()) {
|
||||||
model("shortenRefs", pattern = """^([^\.]+)\.kt$""")
|
model("shortenRefs", pattern = """^([^\.]+)\.kt$""")
|
||||||
}
|
}
|
||||||
|
testClass(javaClass<AbstractAddImportTest>()) {
|
||||||
|
model("addImport", pattern = """^([^\.]+)\.kt$""")
|
||||||
|
}
|
||||||
|
|
||||||
testClass(javaClass<AbstractCompiledKotlinInJavaCompletionTest>()) {
|
testClass(javaClass<AbstractCompiledKotlinInJavaCompletionTest>()) {
|
||||||
model("completion/injava", extension = "java")
|
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.psi.JetDeclaration
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||||
|
|
||||||
private val LOG = Logger.getInstance(javaClass<KotlinCacheService>())
|
private val LOG = Logger.getInstance(javaClass<KotlinCacheService>())
|
||||||
|
|
||||||
@@ -66,6 +67,10 @@ public class KotlinCacheService(val project: Project) {
|
|||||||
return cache.getAnalysisResultsForElements(elements)
|
return cache.getAnalysisResultsForElements(elements)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getFileTopLevelScope(file: JetFile): JetScope {
|
||||||
|
return getLazyResolveSession(file).getScopeProvider().getFileScope(file)
|
||||||
|
}
|
||||||
|
|
||||||
override fun <T> get(extension: CacheExtension<T>): T {
|
override fun <T> get(extension: CacheExtension<T>): T {
|
||||||
return cache[extension]
|
return cache[extension]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|||||||
import org.jetbrains.kotlin.psi.JetDeclaration
|
import org.jetbrains.kotlin.psi.JetDeclaration
|
||||||
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||||
|
|
||||||
public trait ResolutionFacade {
|
public trait ResolutionFacade {
|
||||||
|
|
||||||
@@ -32,6 +34,8 @@ public trait ResolutionFacade {
|
|||||||
|
|
||||||
public fun resolveToDescriptor(declaration: JetDeclaration): DeclarationDescriptor
|
public fun resolveToDescriptor(declaration: JetDeclaration): DeclarationDescriptor
|
||||||
|
|
||||||
|
public fun getFileTopLevelScope(file: JetFile): JetScope
|
||||||
|
|
||||||
public fun findModuleDescriptor(element: JetElement): ModuleDescriptor
|
public fun findModuleDescriptor(element: JetElement): ModuleDescriptor
|
||||||
|
|
||||||
public fun <T> get(extension: CacheExtension<T>): T
|
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.openapi.util.TextRange
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.psi.PsiDocumentManager
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import org.jetbrains.kotlin.analyzer.analyzeInContext
|
import org.jetbrains.kotlin.analyzer.analyzeInContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
||||||
import java.util.LinkedHashSet
|
import java.util.LinkedHashSet
|
||||||
import org.jetbrains.kotlin.resolve.ImportPath
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElement
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
|
||||||
public object ShortenReferences {
|
public object ShortenReferences {
|
||||||
public fun process(element: JetElement) {
|
public fun process(element: JetElement) {
|
||||||
@@ -303,17 +302,9 @@ public object ShortenReferences {
|
|||||||
private var optimizeImports = true
|
private var optimizeImports = true
|
||||||
|
|
||||||
fun addImport(target: DeclarationDescriptor): Boolean {
|
fun addImport(target: DeclarationDescriptor): Boolean {
|
||||||
val realTarget = if (DescriptorUtils.isClassObject(target)) // references to class object are treated as ones to its owner class
|
if (target !is ClassDescriptor && target !is PackageViewDescriptor) return false
|
||||||
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
|
|
||||||
|
|
||||||
optimizeImports()
|
optimizeImports()
|
||||||
ImportInsertHelper.INSTANCE.writeImportToFile(ImportPath(DescriptorUtils.getFqNameSafe(realTarget), false), file)
|
return ImportInsertHelper.INSTANCE.importDescriptor(file, target)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun optimizeImports(): Boolean {
|
fun optimizeImports(): Boolean {
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import org.jetbrains.kotlin.psi.JetFile
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
import org.jetbrains.kotlin.psi.JetImportDirective
|
import org.jetbrains.kotlin.psi.JetImportDirective
|
||||||
import org.jetbrains.kotlin.resolve.ImportPath
|
import org.jetbrains.kotlin.resolve.ImportPath
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade
|
||||||
|
|
||||||
public trait ImportInsertHelper {
|
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 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 {
|
class object {
|
||||||
public val INSTANCE: ImportInsertHelper
|
public val INSTANCE: ImportInsertHelper
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ public class JetCodeStyleSettings extends CustomCodeStyleSettings {
|
|||||||
|
|
||||||
public boolean LBRACE_ON_NEXT_LINE = false;
|
public boolean LBRACE_ON_NEXT_LINE = false;
|
||||||
|
|
||||||
|
public boolean PREFER_ALL_UNDER_IMPORTS = false;
|
||||||
|
|
||||||
public static JetCodeStyleSettings getInstance(Project project) {
|
public static JetCodeStyleSettings getInstance(Project project) {
|
||||||
return CodeStyleSettingsManager.getSettings(project).getCustomSettings(JetCodeStyleSettings.class);
|
return CodeStyleSettingsManager.getSettings(project).getCustomSettings(JetCodeStyleSettings.class);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,32 @@ import com.intellij.codeInsight.CodeInsightSettings
|
|||||||
import com.intellij.codeInsight.actions.OptimizeImportsProcessor
|
import com.intellij.codeInsight.actions.OptimizeImportsProcessor
|
||||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
||||||
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
|
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.name.*
|
import org.jetbrains.kotlin.name.*
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.ImportPath
|
import org.jetbrains.kotlin.resolve.ImportPath
|
||||||
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
|
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 {
|
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())
|
val psiFactory = JetPsiFactory(file.getProject())
|
||||||
if (file is JetCodeFragment) {
|
if (file is JetCodeFragment) {
|
||||||
val newDirective = psiFactory.createImportDirective(importPath)
|
val newDirective = psiFactory.createImportDirective(importPath)
|
||||||
file.addImportsFromString(newDirective.getText())
|
file.addImportsFromString(newDirective.getText())
|
||||||
return
|
return newDirective
|
||||||
}
|
}
|
||||||
|
|
||||||
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())
|
importList.add(psiFactory.createNewLine())
|
||||||
importList.add(newDirective)
|
return importList.add(newDirective) as JetImportDirective
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val newDirective = psiFactory.createImportDirectiveWithImportList(importPath)
|
val newImportList = psiFactory.createImportDirectiveWithImportList(importPath)
|
||||||
val packageDirective = file.getPackageDirective()
|
val packageDirective = file.getPackageDirective()
|
||||||
if (packageDirective == null) {
|
if (packageDirective == null) {
|
||||||
throw IllegalStateException("Scripts are not supported: " + file.getName())
|
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
|
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
|
import java.util.Date
|
||||||
|
|
||||||
val x = <selection>java.sql.Date(1)</selection>
|
val x = <selection>java.sql.Date(1)</selection>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// OPTIMIZE_IMPORTS
|
// OPTIMIZE_IMPORTS: true
|
||||||
import java.sql.Date
|
import java.sql.Date
|
||||||
|
|
||||||
val x = Date(1)
|
val x = Date(1)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// OPTIMIZE_IMPORTS
|
// OPTIMIZE_IMPORTS: true
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
class A : <selection>java.sql.Date</selection>
|
class A : <selection>java.sql.Date</selection>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// OPTIMIZE_IMPORTS
|
// OPTIMIZE_IMPORTS: true
|
||||||
import java.sql.Date
|
import java.sql.Date
|
||||||
|
|
||||||
class A : Date
|
class A : Date
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// OPTIMIZE_IMPORTS
|
// OPTIMIZE_IMPORTS: true
|
||||||
import java.io.*
|
import java.io.*
|
||||||
|
|
||||||
<selection>class A(val d: java.sql.Date, val rs: java.sql.ResultSet)</selection>
|
<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.Date
|
||||||
import java.sql.ResultSet
|
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
|
package org.jetbrains.kotlin.shortenRefs
|
||||||
|
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
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.codeInsight.ShortenReferences
|
||||||
import org.jetbrains.kotlin.idea.JetLightCodeInsightFixtureTestCase
|
import org.jetbrains.kotlin.AbstractImportsTest
|
||||||
import com.intellij.codeInsight.CodeInsightSettings
|
|
||||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
|
||||||
import org.jetbrains.kotlin.test.JetTestUtils
|
|
||||||
|
|
||||||
public abstract class AbstractShortenRefsTest : JetLightCodeInsightFixtureTestCase() {
|
public abstract class AbstractShortenRefsTest : AbstractImportsTest() {
|
||||||
override fun getTestDataPath() = JetTestUtils.getHomeDirectory()
|
override fun doTest(file: JetFile) {
|
||||||
override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
val selectionModel = myFixture.getEditor().getSelectionModel()
|
||||||
|
if (!selectionModel.hasSelection()) error("No selection in input file")
|
||||||
protected fun doTest(testPath: String) {
|
ShortenReferences.process(file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd())
|
||||||
val codeInsightSettings = CodeInsightSettings.getInstance()
|
selectionModel.removeSelection()
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val preferAllUnderImportsDefault: Boolean
|
||||||
|
get() = false
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user