From 5be7eb8a5c2e7451672b621c50d04476da385e45 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 19 Jun 2014 16:17:54 +0400 Subject: [PATCH] Shorten References: Do not optimize imports until shortening is finished #KT-5227 Fixed --- .../com/intellij/codeInsight/annotations.xml | 5 ++ .../plugin/codeInsight/ShortenReferences.kt | 4 +- .../plugin/quickfix/ImportInsertHelper.java | 34 +++++++-- .../imports/leaveQualifiedConstructor.kt | 4 ++ .../leaveQualifiedConstructor.kt.after | 4 ++ .../shortenRefs/imports/leaveQualifiedType.kt | 4 ++ .../imports/leaveQualifiedType.kt.after | 4 ++ .../imports/optimizeMultipleImports.kt | 4 ++ .../imports/optimizeMultipleImports.kt.after | 5 ++ .../shortenRefs/AbstractShortenRefsTest.kt | 72 +++++++++---------- .../shortenRefs/ShortenRefsTestGenerated.java | 26 ++++++- 11 files changed, 119 insertions(+), 47 deletions(-) create mode 100644 annotations/com/intellij/codeInsight/annotations.xml create mode 100644 idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt create mode 100644 idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt.after create mode 100644 idea/testData/shortenRefs/imports/leaveQualifiedType.kt create mode 100644 idea/testData/shortenRefs/imports/leaveQualifiedType.kt.after create mode 100644 idea/testData/shortenRefs/imports/optimizeMultipleImports.kt create mode 100644 idea/testData/shortenRefs/imports/optimizeMultipleImports.kt.after diff --git a/annotations/com/intellij/codeInsight/annotations.xml b/annotations/com/intellij/codeInsight/annotations.xml new file mode 100644 index 00000000000..0ef0480992d --- /dev/null +++ b/annotations/com/intellij/codeInsight/annotations.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt b/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt index 13f1ffa4586..e75d61165c7 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/ShortenReferences.kt @@ -102,6 +102,8 @@ public object ShortenReferences { private fun process(elements: Iterable, elementFilter: (PsiElement) -> FilterResult) { for ((file, fileElements) in elements.groupBy { element -> element.getContainingJetFile() }) { + ImportInsertHelper.optimizeImportsIfNeeded(file) + // first resolve all qualified references - optimization val referenceToContext = JetFileReferencesResolver.resolve(file, fileElements, visitShortNames = false) @@ -348,6 +350,6 @@ public object ShortenReferences { //TODO: do we need this "IfNeeded" check? private fun addImportIfNeeded(descriptor: DeclarationDescriptor, file: JetFile) { - ImportInsertHelper.addImportDirectiveIfNeeded(DescriptorUtils.getFqNameSafe(descriptor), file) + ImportInsertHelper.addImportDirectiveIfNeeded(DescriptorUtils.getFqNameSafe(descriptor), file, false) } } diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java index 2c4fb190de5..66ea97590db 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java @@ -43,12 +43,21 @@ public class ImportInsertHelper { * * @param importFqn full name of the import * @param file File where directive should be added. + * @param optimize Optimize existing imports before adding new one. */ - public static void addImportDirectiveIfNeeded(@NotNull FqName importFqn, @NotNull JetFile file) { - addImportDirectiveIfNeeded(new ImportPath(importFqn, false), file); + public static void addImportDirectiveIfNeeded(@NotNull FqName importFqn, @NotNull JetFile file, boolean optimize) { + addImportDirectiveIfNeeded(new ImportPath(importFqn, false), file, optimize); } - public static void addImportDirectiveOrChangeToFqName(@NotNull FqName importFqn, @NotNull JetFile file, int refOffset, @NotNull PsiElement targetElement) { + public static void addImportDirectiveIfNeeded(@NotNull FqName importFqn, @NotNull JetFile file) { + addImportDirectiveIfNeeded(importFqn, file, true); + } + + public static void addImportDirectiveOrChangeToFqName( + @NotNull FqName importFqn, + @NotNull JetFile file, + int refOffset, + @NotNull PsiElement targetElement) { PsiReference reference = file.findReferenceAt(refOffset); if (reference instanceof JetReference) { PsiElement target = reference.resolve(); @@ -80,12 +89,12 @@ public class ImportInsertHelper { return; } } - addImportDirectiveIfNeeded(new ImportPath(importFqn, false), file); + addImportDirectiveIfNeeded(importFqn, file); } - public static void addImportDirectiveIfNeeded(@NotNull ImportPath importPath, @NotNull JetFile file) { - if (CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY) { - new OptimizeImportsProcessor(file.getProject(), file).runWithoutProgress(); + public static void addImportDirectiveIfNeeded(@NotNull ImportPath importPath, @NotNull JetFile file, boolean optimize) { + if (optimize) { + optimizeImportsIfNeeded(file); } if (!needImport(importPath, file)) { @@ -95,6 +104,16 @@ public class ImportInsertHelper { writeImportToFile(importPath, file); } + public static void optimizeImportsIfNeeded(JetFile file) { + if (CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY) { + optimizeImports(file); + } + } + + public static void optimizeImports(JetFile file) { + new OptimizeImportsProcessor(file.getProject(), file).runWithoutProgress(); + } + public static void writeImportToFile(@NotNull ImportPath importPath, @NotNull JetFile file) { if (file instanceof JetCodeFragment) { JetImportDirective newDirective = JetPsiFactory.createImportDirective(file.getProject(), importPath); @@ -105,6 +124,7 @@ public class ImportInsertHelper { JetImportList importList = file.getImportList(); if (importList != null) { JetImportDirective newDirective = JetPsiFactory.createImportDirective(file.getProject(), importPath); + importList.add(JetPsiFactory.createNewLine(file.getProject())); importList.add(newDirective); } else { diff --git a/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt b/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt new file mode 100644 index 00000000000..0d08370f9a1 --- /dev/null +++ b/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt @@ -0,0 +1,4 @@ +// OPTIMIZE_IMPORTS +import java.util.Date + +val x = java.sql.Date(1) diff --git a/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt.after b/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt.after new file mode 100644 index 00000000000..0bce500e37a --- /dev/null +++ b/idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt.after @@ -0,0 +1,4 @@ +// OPTIMIZE_IMPORTS +import java.sql.Date + +val x = Date(1) diff --git a/idea/testData/shortenRefs/imports/leaveQualifiedType.kt b/idea/testData/shortenRefs/imports/leaveQualifiedType.kt new file mode 100644 index 00000000000..94bee0a3da3 --- /dev/null +++ b/idea/testData/shortenRefs/imports/leaveQualifiedType.kt @@ -0,0 +1,4 @@ +// OPTIMIZE_IMPORTS +import java.util.Date + +class A : java.sql.Date \ No newline at end of file diff --git a/idea/testData/shortenRefs/imports/leaveQualifiedType.kt.after b/idea/testData/shortenRefs/imports/leaveQualifiedType.kt.after new file mode 100644 index 00000000000..baf93cfc2c9 --- /dev/null +++ b/idea/testData/shortenRefs/imports/leaveQualifiedType.kt.after @@ -0,0 +1,4 @@ +// OPTIMIZE_IMPORTS +import java.sql.Date + +class A : Date \ No newline at end of file diff --git a/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt b/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt new file mode 100644 index 00000000000..7d2b6bb180f --- /dev/null +++ b/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt @@ -0,0 +1,4 @@ +// OPTIMIZE_IMPORTS +import java.io.* + +class A(val d: java.sql.Date, val rs: java.sql.ResultSet) diff --git a/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt.after b/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt.after new file mode 100644 index 00000000000..e421fe4a1e0 --- /dev/null +++ b/idea/testData/shortenRefs/imports/optimizeMultipleImports.kt.after @@ -0,0 +1,5 @@ +// OPTIMIZE_IMPORTS +import java.sql.Date +import java.sql.ResultSet + +class A(val d: Date, val rs: ResultSet) diff --git a/idea/tests/org/jetbrains/jet/shortenRefs/AbstractShortenRefsTest.kt b/idea/tests/org/jetbrains/jet/shortenRefs/AbstractShortenRefsTest.kt index 214941370ee..e733742adef 100644 --- a/idea/tests/org/jetbrains/jet/shortenRefs/AbstractShortenRefsTest.kt +++ b/idea/tests/org/jetbrains/jet/shortenRefs/AbstractShortenRefsTest.kt @@ -17,59 +17,55 @@ package org.jetbrains.jet.shortenRefs import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase -import org.jetbrains.jet.InTextDirectivesUtils -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor -import org.jetbrains.jet.lang.psi.JetSimpleNameExpression -import org.jetbrains.jet.lang.psi.JetExpression -import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache import org.jetbrains.jet.lang.psi.JetFile -import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils -import org.jetbrains.jet.lang.resolve.name.FqName -import org.jetbrains.jet.plugin.project.TargetPlatform import org.jetbrains.jet.plugin.JetWithJdkAndRuntimeLightProjectDescriptor -import org.jetbrains.jet.lang.resolve.name.Name -import com.intellij.util.containers.Predicate -import org.jetbrains.jet.lang.descriptors.ClassDescriptor -import com.intellij.openapi.application.Application import com.intellij.openapi.application.ApplicationManager -import org.jetbrains.jet.plugin.PluginTestCaseBase import java.io.File import com.intellij.openapi.command.CommandProcessor -import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.jet.lang.psi.JetReferenceExpression -import com.intellij.psi.PsiElement import org.jetbrains.jet.plugin.codeInsight.ShortenReferences -import org.jetbrains.jet.lang.psi.JetElement import org.jetbrains.jet.JetTestCaseBuilder +import com.intellij.codeInsight.CodeInsightSettings +import org.jetbrains.jet.InTextDirectivesUtils abstract class AbstractShortenRefsTest : LightCodeInsightFixtureTestCase() { override fun getTestDataPath() = JetTestCaseBuilder.getHomeDirectory() override fun getProjectDescriptor() = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE protected fun doTest(testPath: String) { - 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) - } + val codeInsightSettings = CodeInsightSettings.getInstance() + val optimizeImportsBefore = codeInsightSettings.OPTIMIZE_IMPORTS_ON_THE_FLY - fixture.configureByFile(testPath) - - val file = fixture.getFile() as JetFile - val selectionModel = fixture.getEditor().getSelectionModel() - if (!selectionModel.hasSelection()) error("No selection in input file") - - CommandProcessor.getInstance().executeCommand(getProject(), { - ApplicationManager.getApplication()!!.runWriteAction { - ShortenReferences.process(file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()) + 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) } - }, null, null) - selectionModel.removeSelection() - fixture.checkResultByFile(testPath + ".after") + 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 + } } } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/shortenRefs/ShortenRefsTestGenerated.java b/idea/tests/org/jetbrains/jet/shortenRefs/ShortenRefsTestGenerated.java index b7af568ad50..03e71a462e5 100644 --- a/idea/tests/org/jetbrains/jet/shortenRefs/ShortenRefsTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/shortenRefs/ShortenRefsTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.shortenRefs.AbstractShortenRefsTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("idea/testData/shortenRefs") -@InnerTestClasses({ShortenRefsTestGenerated.Constructor.class, ShortenRefsTestGenerated.Java.class, ShortenRefsTestGenerated.Type.class}) +@InnerTestClasses({ShortenRefsTestGenerated.Constructor.class, ShortenRefsTestGenerated.Imports.class, ShortenRefsTestGenerated.Java.class, ShortenRefsTestGenerated.Type.class}) public class ShortenRefsTestGenerated extends AbstractShortenRefsTest { public void testAllFilesPresentInShortenRefs() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/shortenRefs"), Pattern.compile("^([^\\.]+)\\.kt$"), true); @@ -130,6 +130,29 @@ public class ShortenRefsTestGenerated extends AbstractShortenRefsTest { } + @TestMetadata("idea/testData/shortenRefs/imports") + public static class Imports extends AbstractShortenRefsTest { + public void testAllFilesPresentInImports() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/shortenRefs/imports"), Pattern.compile("^([^\\.]+)\\.kt$"), true); + } + + @TestMetadata("leaveQualifiedConstructor.kt") + public void testLeaveQualifiedConstructor() throws Exception { + doTest("idea/testData/shortenRefs/imports/leaveQualifiedConstructor.kt"); + } + + @TestMetadata("leaveQualifiedType.kt") + public void testLeaveQualifiedType() throws Exception { + doTest("idea/testData/shortenRefs/imports/leaveQualifiedType.kt"); + } + + @TestMetadata("optimizeMultipleImports.kt") + public void testOptimizeMultipleImports() throws Exception { + doTest("idea/testData/shortenRefs/imports/optimizeMultipleImports.kt"); + } + + } + @TestMetadata("idea/testData/shortenRefs/java") public static class Java extends AbstractShortenRefsTest { public void testAllFilesPresentInJava() throws Exception { @@ -275,6 +298,7 @@ public class ShortenRefsTestGenerated extends AbstractShortenRefsTest { TestSuite suite = new TestSuite("ShortenRefsTestGenerated"); suite.addTestSuite(ShortenRefsTestGenerated.class); suite.addTestSuite(Constructor.class); + suite.addTestSuite(Imports.class); suite.addTestSuite(Java.class); suite.addTestSuite(Type.class); return suite;