From 09a99ae6057c02ae929b1ffa11879202fcc1c301 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 27 Jan 2015 14:14:54 +0300 Subject: [PATCH] Moved import policy into ImportInsertHelper --- .../idea/codeInsight/ShortenReferences.kt | 18 +++++-------- .../idea/quickfix/ImportInsertHelper.kt | 26 +++++++++++-------- idea/src/META-INF/plugin.xml | 2 +- .../kotlin/idea/actions/JetAddImportAction.kt | 2 +- .../KotlinCopyPasteReferenceProcessor.kt | 4 +-- .../idea/completion/CompletionSorting.kt | 2 +- .../handlers/KotlinCallableInsertHandler.kt | 2 +- .../idea/formatter/JetCodeStyleSettings.java | 1 + .../idea/imports/KotlinImportOptimizer.kt | 5 ++-- .../idea/quickfix/ImportInsertHelperImpl.kt | 24 +++++++++++------ .../kotlin/idea/refactoring/move/moveUtils.kt | 2 +- .../kotlin/addImport/AbstractAddImportTest.kt | 2 +- ...AbstractEditorForEvaluateExpressionTest.kt | 2 +- .../imports/OptimizeImportsOnFlyTest.java | 2 +- .../idea/quickfix/ImportClassHelperTest.java | 6 ++--- 15 files changed, 55 insertions(+), 45 deletions(-) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/codeInsight/ShortenReferences.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/codeInsight/ShortenReferences.kt index 62f7950ec81..c3b253341e2 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/codeInsight/ShortenReferences.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/codeInsight/ShortenReferences.kt @@ -160,7 +160,7 @@ public object ShortenReferences { if (canShortenNow) { elementsToShorten.add(element) } - else if (target !in failedToImportDescriptors && mayImport(target)) { + else if (target !in failedToImportDescriptors && mayImport(target, file)) { descriptorsToImport.add(target) } else { @@ -295,29 +295,25 @@ public object ShortenReferences { ?: listOf() } - //TODO: move into ImportInsertHelper - private fun mayImport(descriptor: DeclarationDescriptor): Boolean { - return when (descriptor) { - is ClassDescriptor -> descriptor.getContainingDeclaration() is PackageFragmentDescriptor - is PackageViewDescriptor -> true //TODO: option - else -> false - } + private fun mayImport(descriptor: DeclarationDescriptor, file: JetFile): Boolean { + if (descriptor !is ClassDescriptor && descriptor !is PackageViewDescriptor) return false + return ImportInsertHelper.getInstance(file.getProject()).mayImportByCodeStyle(descriptor) } // this class is needed to optimize imports only when we actually insert any import (optimization) private class ImportInserter(val file: JetFile) { private var optimizeImports = true + private val helper = ImportInsertHelper.getInstance(file.getProject()) fun addImport(target: DeclarationDescriptor): ImportInsertHelper.ImportDescriptorResult { - if (!mayImport(target)) return ImportInsertHelper.ImportDescriptorResult.FAIL optimizeImports() - return ImportInsertHelper.INSTANCE.importDescriptor(file, target) + return helper.importDescriptor(file, target) } fun optimizeImports(): Boolean { if (!optimizeImports) return false optimizeImports = false - return ImportInsertHelper.INSTANCE.optimizeImportsOnTheFly(file) + return helper.optimizeImportsOnTheFly(file) } } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelper.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelper.kt index 0e9666f6bcb..bd83ead729d 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelper.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelper.kt @@ -16,27 +16,30 @@ package org.jetbrains.kotlin.idea.quickfix -import com.intellij.openapi.components.ServiceManager 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 +import com.intellij.openapi.project.Project +import com.intellij.openapi.components.ServiceManager +import kotlin.platform.platformStatic -public trait ImportInsertHelper { +public abstract class ImportInsertHelper { - public fun addImportDirectiveIfNeeded(importFqn: FqName, file: JetFile) + public abstract fun addImportDirectiveIfNeeded(importFqn: FqName, file: JetFile) - public fun optimizeImportsOnTheFly(file: JetFile): Boolean + public abstract fun optimizeImportsOnTheFly(file: JetFile): Boolean - public fun isImportedWithDefault(importPath: ImportPath, contextFile: JetFile): Boolean + public abstract fun isImportedWithDefault(importPath: ImportPath, contextFile: JetFile): Boolean public fun needImport(fqName: FqName, file: JetFile): Boolean = needImport(ImportPath(fqName, false), file) - public fun needImport(importPath: ImportPath, file: JetFile, importDirectives: List = file.getImportDirectives()): Boolean + public abstract fun needImport(importPath: ImportPath, file: JetFile, importDirectives: List = file.getImportDirectives()): Boolean - public fun writeImportToFile(importPath: ImportPath, file: JetFile): JetImportDirective + public abstract fun writeImportToFile(importPath: ImportPath, file: JetFile): JetImportDirective + + public abstract fun mayImportByCodeStyle(descriptor: DeclarationDescriptor): Boolean public enum class ImportDescriptorResult { FAIL @@ -44,10 +47,11 @@ public trait ImportInsertHelper { ALREADY_IMPORTED } - public fun importDescriptor(file: JetFile, descriptor: DeclarationDescriptor): ImportDescriptorResult + public abstract fun importDescriptor(file: JetFile, descriptor: DeclarationDescriptor): ImportDescriptorResult class object { - public val INSTANCE: ImportInsertHelper - get() = ServiceManager.getService(javaClass()) + [platformStatic] + public fun getInstance(project: Project): ImportInsertHelper + = ServiceManager.getService(project, javaClass()) } } diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 351da25c534..15c60da75b8 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -142,7 +142,7 @@ - , file: JetFile) { for ((referenceExpression, fqName, shouldLengthen) in referencesToRestore) { if (!shouldLengthen) { - ImportInsertHelper.INSTANCE.addImportDirectiveIfNeeded(fqName, file) + ImportInsertHelper.getInstance(file.getProject()).addImportDirectiveIfNeeded(fqName, file) } else { //TODO: try to shorten reference after (sometimes is possible), need shorten reference to support all relevant cases diff --git a/idea/src/org/jetbrains/kotlin/idea/completion/CompletionSorting.kt b/idea/src/org/jetbrains/kotlin/idea/completion/CompletionSorting.kt index 6d32784456d..9739becd04b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/completion/CompletionSorting.kt +++ b/idea/src/org/jetbrains/kotlin/idea/completion/CompletionSorting.kt @@ -150,7 +150,7 @@ private class JetDeclarationRemotenessWeigher(private val file: JetFile) : Looku val fqName = importPath.fqnPart() return when { JavaToKotlinClassMap.INSTANCE.mapPlatformClass(fqName).isNotEmpty() -> Weight.notToBeUsedInKotlin - ImportInsertHelper.INSTANCE.isImportedWithDefault(importPath, file) -> Weight.kotlinDefaultImport + ImportInsertHelper.getInstance(file.getProject()).isImportedWithDefault(importPath, file) -> Weight.kotlinDefaultImport importCache.isImportedWithPreciseImport(fqName) -> Weight.preciseImport importCache.isImportedWithAllUnderImport(fqName) -> Weight.allUnderImport importCache.hasPreciseImportFromPackage(fqName.parent()) -> Weight.hasImportFromSamePackage diff --git a/idea/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinCallableInsertHandler.kt b/idea/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinCallableInsertHandler.kt index 386807abea5..a29855baa22 100644 --- a/idea/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinCallableInsertHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinCallableInsertHandler.kt @@ -77,7 +77,7 @@ public abstract class KotlinCallableInsertHandler : BaseDeclarationInsertHandler if (DescriptorUtils.isTopLevelDeclaration(descriptor)) { ApplicationManager.getApplication()?.runWriteAction { - ImportInsertHelper.INSTANCE.addImportDirectiveIfNeeded(DescriptorUtils.getFqNameSafe(descriptor), file) + ImportInsertHelper.getInstance(context.getProject()).addImportDirectiveIfNeeded(DescriptorUtils.getFqNameSafe(descriptor), file) } } } diff --git a/idea/src/org/jetbrains/kotlin/idea/formatter/JetCodeStyleSettings.java b/idea/src/org/jetbrains/kotlin/idea/formatter/JetCodeStyleSettings.java index f5a096be5a0..47147f47124 100644 --- a/idea/src/org/jetbrains/kotlin/idea/formatter/JetCodeStyleSettings.java +++ b/idea/src/org/jetbrains/kotlin/idea/formatter/JetCodeStyleSettings.java @@ -42,6 +42,7 @@ public class JetCodeStyleSettings extends CustomCodeStyleSettings { public boolean LBRACE_ON_NEXT_LINE = false; public boolean PREFER_ALL_UNDER_IMPORTS = false; + public boolean IMPORT_PACKAGES = true; public static JetCodeStyleSettings getInstance(Project project) { return CodeStyleSettingsManager.getSettings(project).getCustomSettings(JetCodeStyleSettings.class); diff --git a/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt b/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt index 054092c92aa..5ead5152afe 100644 --- a/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt @@ -44,6 +44,7 @@ public class KotlinImportOptimizer() : ImportOptimizer { val directivesAfterCurrent = ArrayList(jetFile.getImportDirectives()) ApplicationManager.getApplication()!!.runWriteAction(Runnable { + val importInsertHelper = ImportInsertHelper.getInstance(file.getProject()) // Remove only unnecessary imports for (anImport in directives) { directivesAfterCurrent.remove(anImport) @@ -54,8 +55,8 @@ public class KotlinImportOptimizer() : ImportOptimizer { } if (isUseful(importPath, usedQualifiedNames) - && ImportInsertHelper.INSTANCE.needImport(importPath, jetFile, directivesBeforeCurrent) - && ImportInsertHelper.INSTANCE.needImport(importPath, jetFile, directivesAfterCurrent) + && importInsertHelper.needImport(importPath, jetFile, directivesBeforeCurrent) + && importInsertHelper.needImport(importPath, jetFile, directivesAfterCurrent) ) { directivesBeforeCurrent.add(anImport) } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelperImpl.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelperImpl.kt index 89a1c1cad88..9d88e1f51ea 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelperImpl.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportInsertHelperImpl.kt @@ -50,8 +50,10 @@ import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility import org.jetbrains.kotlin.idea.quickfix.ImportInsertHelper.ImportDescriptorResult +import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor +import com.intellij.openapi.project.Project -public class ImportInsertHelperImpl : ImportInsertHelper { +public class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper() { /** * Add import directive into the PSI tree for the given package. * @@ -70,7 +72,7 @@ public class ImportInsertHelperImpl : ImportInsertHelper { override fun optimizeImportsOnTheFly(file: JetFile): Boolean { if (CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY) { - OptimizeImportsProcessor(file.getProject(), file).runWithoutProgress() + OptimizeImportsProcessor(project, file).runWithoutProgress() return true } else { @@ -79,7 +81,7 @@ public class ImportInsertHelperImpl : ImportInsertHelper { } override fun writeImportToFile(importPath: ImportPath, file: JetFile): JetImportDirective { - val psiFactory = JetPsiFactory(file.getProject()) + val psiFactory = JetPsiFactory(project) if (file is JetCodeFragment) { val newDirective = psiFactory.createImportDirective(importPath) file.addImportsFromString(newDirective.getText()) @@ -153,6 +155,15 @@ public class ImportInsertHelperImpl : ImportInsertHelper { return true } + override fun mayImportByCodeStyle(descriptor: DeclarationDescriptor): Boolean { + val importable = descriptor.getImportableDescriptor() + return when (importable) { + is ClassDescriptor -> importable.getContainingDeclaration() is PackageFragmentDescriptor // do not import nested classes + is PackageViewDescriptor -> JetCodeStyleSettings.getInstance(project).IMPORT_PACKAGES + else -> true + } + } + override fun importDescriptor(file: JetFile, descriptor: DeclarationDescriptor): ImportDescriptorResult { return Importer(file).importDescriptor(descriptor) } @@ -161,13 +172,10 @@ public class ImportInsertHelperImpl : ImportInsertHelper { private val file: JetFile ) { private val resolutionFacade = file.getResolutionFacade() - private val preferAllUnderImports = JetCodeStyleSettings.getInstance(file.getProject()).PREFER_ALL_UNDER_IMPORTS + private val preferAllUnderImports = JetCodeStyleSettings.getInstance(project).PREFER_ALL_UNDER_IMPORTS fun importDescriptor(descriptor: DeclarationDescriptor): ImportDescriptorResult { - val target = if (DescriptorUtils.isClassObject(descriptor)) // references to class object are treated as ones to its owner class - descriptor.getContainingDeclaration() as? ClassDescriptor ?: return ImportDescriptorResult.FAIL - else - descriptor + val target = descriptor.getImportableDescriptor() val name = target.getName() val topLevelScope = resolutionFacade.getFileTopLevelScope(file) diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveUtils.kt index 034b634f54c..c71edd8598a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveUtils.kt @@ -212,7 +212,7 @@ fun postProcessMoveUsages(usages: List, is MoveRenameUsageInfoForExtension -> { val element = counterpart(usage.getReferencedElement()!!) val file = with(usage) { if (addImportToOriginalFile) originalFile else counterpart(originalFile) } as JetFile - ImportInsertHelper.INSTANCE.addImportDirectiveIfNeeded(element.getKotlinFqName()!!, file) + ImportInsertHelper.getInstance(element.getProject()).addImportDirectiveIfNeeded(element.getKotlinFqName()!!, file) } is MoveRenameUsageInfo -> { diff --git a/idea/tests/org/jetbrains/kotlin/addImport/AbstractAddImportTest.kt b/idea/tests/org/jetbrains/kotlin/addImport/AbstractAddImportTest.kt index de50a7a39f2..224ea020411 100644 --- a/idea/tests/org/jetbrains/kotlin/addImport/AbstractAddImportTest.kt +++ b/idea/tests/org/jetbrains/kotlin/addImport/AbstractAddImportTest.kt @@ -57,7 +57,7 @@ public abstract class AbstractAddImportTest : AbstractImportsTest() { 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()) != ImportInsertHelper.ImportDescriptorResult.FAIL + val success = ImportInsertHelper.getInstance(getProject()).importDescriptor(file, descriptors.single()) != ImportInsertHelper.ImportDescriptorResult.FAIL if (!success) { val document = PsiDocumentManager.getInstance(getProject()).getDocument(file) document.replaceString(0, document.getTextLength(), "Failed to add import") diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractEditorForEvaluateExpressionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractEditorForEvaluateExpressionTest.kt index 26365bc2d69..6454882bf5b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractEditorForEvaluateExpressionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/AbstractEditorForEvaluateExpressionTest.kt @@ -50,7 +50,7 @@ public abstract class AbstractCodeFragmentHighlightingTest : AbstractJetPsiCheck ApplicationManager.getApplication()?.runWriteAction { val fileText = FileUtil.loadFile(File(filePath), true) InTextDirectivesUtils.findListWithPrefixes(fileText, "// IMPORT: ").forEach { - ImportInsertHelper.INSTANCE.addImportDirectiveIfNeeded(FqName(it), (myFixture.getFile() as JetFile)) + ImportInsertHelper.getInstance(getProject()).addImportDirectiveIfNeeded(FqName(it), (myFixture.getFile() as JetFile)) } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/imports/OptimizeImportsOnFlyTest.java b/idea/tests/org/jetbrains/kotlin/idea/imports/OptimizeImportsOnFlyTest.java index b0df46e9e4a..6daac93ada3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/imports/OptimizeImportsOnFlyTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/imports/OptimizeImportsOnFlyTest.java @@ -33,7 +33,7 @@ public class OptimizeImportsOnFlyTest extends LightDaemonAnalyzerTestCase { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - ImportInsertHelper.OBJECT$.getINSTANCE().addImportDirectiveIfNeeded(new FqName("java.util.HashSet"), (JetFile) getFile()); + ImportInsertHelper.getInstance(getProject()).addImportDirectiveIfNeeded(new FqName("java.util.HashSet"), (JetFile) getFile()); } }); } diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/ImportClassHelperTest.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/ImportClassHelperTest.java index 8b3f0ae98c4..3cdca761ee3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/ImportClassHelperTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/ImportClassHelperTest.java @@ -46,7 +46,7 @@ public class ImportClassHelperTest extends LightDaemonAnalyzerTestCase { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - ImportInsertHelper.OBJECT$.getINSTANCE().addImportDirectiveIfNeeded(new FqName("java.util.ArrayList"), (JetFile) getFile()); + ImportInsertHelper.getInstance(getProject()).addImportDirectiveIfNeeded(new FqName("java.util.ArrayList"), (JetFile) getFile()); } }); @@ -58,7 +58,7 @@ public class ImportClassHelperTest extends LightDaemonAnalyzerTestCase { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - ImportInsertHelper.OBJECT$.getINSTANCE().addImportDirectiveIfNeeded(new FqName("java.util.ArrayList"), (JetFile) getFile()); + ImportInsertHelper.getInstance(getProject()).addImportDirectiveIfNeeded(new FqName("java.util.ArrayList"), (JetFile) getFile()); } }); @@ -70,7 +70,7 @@ public class ImportClassHelperTest extends LightDaemonAnalyzerTestCase { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { - ImportInsertHelper.OBJECT$.getINSTANCE().addImportDirectiveIfNeeded(new FqName(importString), (JetFile) getFile()); + ImportInsertHelper.getInstance(getProject()).addImportDirectiveIfNeeded(new FqName(importString), (JetFile) getFile()); } }); checkResultByFile(getTestName(false) + ".kt.after");