From 2a5b76bf12b4f1664b84f16ff1817559de80476e Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Mon, 17 Aug 2015 19:21:06 +0300 Subject: [PATCH 1/3] Optimize imports on the fly --- src/META-INF/plugin.xml | 7 +++ .../imports/GoAutoImportConfigurable.java | 6 ++ .../imports/GoCodeInsightSettings.java | 9 +++ .../imports/GoOptimizeImportsPass.java | 47 ++++++++++++++ .../imports/GoOptimizeImportsPassFactory.java | 54 ++++++++++++++++ .../on-the-fly/redeclaredImport-after.go | 10 +++ .../optimize/on-the-fly/redeclaredImport.go | 11 ++++ .../on-the-fly/redundantImport-after.go | 10 +++ .../optimize/on-the-fly/redundantImport.go | 10 +++ .../optimize/on-the-fly/unusedImport-after.go | 4 ++ .../optimize/on-the-fly/unusedImport.go | 5 ++ .../GoOptimizeImportsOnTheFlyTest.java | 63 +++++++++++++++++++ 12 files changed, 236 insertions(+) create mode 100644 src/com/goide/codeInsight/imports/GoOptimizeImportsPass.java create mode 100644 src/com/goide/codeInsight/imports/GoOptimizeImportsPassFactory.java create mode 100644 testData/imports/optimize/on-the-fly/redeclaredImport-after.go create mode 100644 testData/imports/optimize/on-the-fly/redeclaredImport.go create mode 100644 testData/imports/optimize/on-the-fly/redundantImport-after.go create mode 100644 testData/imports/optimize/on-the-fly/redundantImport.go create mode 100644 testData/imports/optimize/on-the-fly/unusedImport-after.go create mode 100644 testData/imports/optimize/on-the-fly/unusedImport.go create mode 100644 tests/com/goide/codeInsight/imports/GoOptimizeImportsOnTheFlyTest.java diff --git a/src/META-INF/plugin.xml b/src/META-INF/plugin.xml index 350a0d85ec..e1e78292dd 100644 --- a/src/META-INF/plugin.xml +++ b/src/META-INF/plugin.xml @@ -52,6 +52,13 @@ + + + com.goide.codeInsight.imports.GoOptimizeImportsPassFactory + + + + diff --git a/src/com/goide/codeInsight/imports/GoAutoImportConfigurable.java b/src/com/goide/codeInsight/imports/GoAutoImportConfigurable.java index 92734d77fa..f938d27c44 100644 --- a/src/com/goide/codeInsight/imports/GoAutoImportConfigurable.java +++ b/src/com/goide/codeInsight/imports/GoAutoImportConfigurable.java @@ -37,6 +37,7 @@ public class GoAutoImportConfigurable implements SearchableConfigurable { private JCheckBox myCbShowImportPopup; + private JCheckBox myCbOptimizeImportsOnTheFly; private JCheckBox myCbAddUnambiguousImports; private JBList myExcludePackagesList; private DefaultListModel myExcludePackagesModel; @@ -58,8 +59,10 @@ public GoAutoImportConfigurable(@NotNull Project project, boolean dialogMode) { public JComponent createComponent() { FormBuilder builder = FormBuilder.createFormBuilder(); myCbShowImportPopup = new JCheckBox(ApplicationBundle.message("checkbox.show.import.popup")); + myCbOptimizeImportsOnTheFly = new JCheckBox(ApplicationBundle.message("checkbox.optimize.imports.on.the.fly")); myCbAddUnambiguousImports = new JCheckBox(ApplicationBundle.message("checkbox.add.unambiguous.imports.on.the.fly")); builder.addComponent(myCbShowImportPopup); + builder.addComponent(myCbOptimizeImportsOnTheFly); builder.addComponent(myCbAddUnambiguousImports); myExcludePackagesList = new JBList(); @@ -94,6 +97,7 @@ private String[] getExcludedPackages() { @Override public boolean isModified() { return myCodeInsightSettings.isShowImportPopup() != myCbShowImportPopup.isSelected() || + myCodeInsightSettings.isOptimizeImportsOnTheFly() != myCbOptimizeImportsOnTheFly.isSelected() || myCodeInsightSettings.isAddUnambiguousImportsOnTheFly() != myCbAddUnambiguousImports.isSelected() || !Arrays.equals(getExcludedPackages(), myExcludedSettings.getExcludedPackages()); } @@ -101,6 +105,7 @@ public boolean isModified() { @Override public void apply() throws ConfigurationException { myCodeInsightSettings.setShowImportPopup(myCbShowImportPopup.isSelected()); + myCodeInsightSettings.setOptimizeImportsOnTheFly(myCbOptimizeImportsOnTheFly.isSelected()); myCodeInsightSettings.setAddUnambiguousImportsOnTheFly(myCbAddUnambiguousImports.isSelected()); myExcludedSettings.setExcludedPackages(getExcludedPackages()); } @@ -108,6 +113,7 @@ public void apply() throws ConfigurationException { @Override public void reset() { myCbShowImportPopup.setSelected(myCodeInsightSettings.isShowImportPopup()); + myCbOptimizeImportsOnTheFly.setSelected(myCodeInsightSettings.isOptimizeImportsOnTheFly()); myCbAddUnambiguousImports.setSelected(myCodeInsightSettings.isAddUnambiguousImportsOnTheFly()); myExcludePackagesModel = new DefaultListModel(); diff --git a/src/com/goide/codeInsight/imports/GoCodeInsightSettings.java b/src/com/goide/codeInsight/imports/GoCodeInsightSettings.java index e5ff2532be..041261fbab 100644 --- a/src/com/goide/codeInsight/imports/GoCodeInsightSettings.java +++ b/src/com/goide/codeInsight/imports/GoCodeInsightSettings.java @@ -26,6 +26,7 @@ ) public class GoCodeInsightSettings implements PersistentStateComponent { private boolean myShowImportPopup = true; + private boolean myOptimizeImportsOnTheFly = false; private boolean myAddUnambiguousImportsOnTheFly = true; public static GoCodeInsightSettings getInstance() { @@ -51,6 +52,14 @@ public void setShowImportPopup(boolean showImportPopup) { myShowImportPopup = showImportPopup; } + public boolean isOptimizeImportsOnTheFly() { + return myOptimizeImportsOnTheFly; + } + + public void setOptimizeImportsOnTheFly(boolean optimizeImportsOnTheFly) { + myOptimizeImportsOnTheFly = optimizeImportsOnTheFly; + } + public boolean isAddUnambiguousImportsOnTheFly() { return myAddUnambiguousImportsOnTheFly; } diff --git a/src/com/goide/codeInsight/imports/GoOptimizeImportsPass.java b/src/com/goide/codeInsight/imports/GoOptimizeImportsPass.java new file mode 100644 index 0000000000..26d33fd2b5 --- /dev/null +++ b/src/com/goide/codeInsight/imports/GoOptimizeImportsPass.java @@ -0,0 +1,47 @@ +/* + * Copyright 2013-2015 Sergey Ignatov, Alexander Zolotov, Mihai Toader, Florin Patan + * + * 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 com.goide.codeInsight.imports; + +import com.intellij.codeInsight.daemon.impl.DefaultHighlightInfoProcessor; +import com.intellij.codeInsight.daemon.impl.ProgressableTextEditorHighlightingPass; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiFile; +import com.intellij.util.DocumentUtil; +import org.jetbrains.annotations.NotNull; + +public class GoOptimizeImportsPass extends ProgressableTextEditorHighlightingPass { + @NotNull private final PsiFile myFile; + + public GoOptimizeImportsPass(@NotNull Project project, @NotNull PsiFile file, @NotNull Editor editor) { + super(project, editor.getDocument(), "Go Optimize Imports Pass", file, editor, file.getTextRange(), false, + new DefaultHighlightInfoProcessor()); + myFile = file; + } + + @Override + protected void collectInformationWithProgress(@NotNull ProgressIndicator progress) { + progress.checkCanceled(); + } + + @Override + protected void applyInformationWithProgress() { + final Runnable runnable = new GoImportOptimizer().processFile(myFile); + DocumentUtil.writeInRunUndoTransparentAction(runnable); + } +} diff --git a/src/com/goide/codeInsight/imports/GoOptimizeImportsPassFactory.java b/src/com/goide/codeInsight/imports/GoOptimizeImportsPassFactory.java new file mode 100644 index 0000000000..fc9fdd78a8 --- /dev/null +++ b/src/com/goide/codeInsight/imports/GoOptimizeImportsPassFactory.java @@ -0,0 +1,54 @@ +/* + * Copyright 2013-2015 Sergey Ignatov, Alexander Zolotov, Mihai Toader, Florin Patan + * + * 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 com.goide.codeInsight.imports; + +import com.goide.psi.GoFile; +import com.intellij.codeHighlighting.Pass; +import com.intellij.codeHighlighting.TextEditorHighlightingPass; +import com.intellij.codeHighlighting.TextEditorHighlightingPassFactory; +import com.intellij.codeHighlighting.TextEditorHighlightingPassRegistrar; +import com.intellij.codeInsight.daemon.impl.FileStatusMap; +import com.intellij.openapi.components.AbstractProjectComponent; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class GoOptimizeImportsPassFactory extends AbstractProjectComponent implements TextEditorHighlightingPassFactory { + protected GoOptimizeImportsPassFactory(Project project, TextEditorHighlightingPassRegistrar highlightingPassRegistrar) { + super(project); + highlightingPassRegistrar.registerTextEditorHighlightingPass(this, new int[]{Pass.UPDATE_ALL}, null, false, -1); + } + + @Nullable + @Override + public TextEditorHighlightingPass createHighlightingPass(@NotNull PsiFile file, @NotNull Editor editor) { + TextRange range = FileStatusMap.getDirtyTextRange(editor, Pass.UPDATE_ALL); + if (range != null && file instanceof GoFile && GoCodeInsightSettings.getInstance().isOptimizeImportsOnTheFly()) { + return new GoOptimizeImportsPass(file.getProject(), file, editor); + } + return null; + } + + @NotNull + @Override + public String getComponentName() { + return "OptimizeImportsPassFactory"; + } +} diff --git a/testData/imports/optimize/on-the-fly/redeclaredImport-after.go b/testData/imports/optimize/on-the-fly/redeclaredImport-after.go new file mode 100644 index 0000000000..7e9335a425 --- /dev/null +++ b/testData/imports/optimize/on-the-fly/redeclaredImport-after.go @@ -0,0 +1,10 @@ +package a +import ( + "fmt" + "http" +) + +func b() { + http.get("123") + fmt.Println() +} \ No newline at end of file diff --git a/testData/imports/optimize/on-the-fly/redeclaredImport.go b/testData/imports/optimize/on-the-fly/redeclaredImport.go new file mode 100644 index 0000000000..93d0327847 --- /dev/null +++ b/testData/imports/optimize/on-the-fly/redeclaredImport.go @@ -0,0 +1,11 @@ +package a +import ( + fmt "fmt" + "fmt" + "http" +) + +func b() { + http.get("123") + fmt.Println() +} \ No newline at end of file diff --git a/testData/imports/optimize/on-the-fly/redundantImport-after.go b/testData/imports/optimize/on-the-fly/redundantImport-after.go new file mode 100644 index 0000000000..7e9335a425 --- /dev/null +++ b/testData/imports/optimize/on-the-fly/redundantImport-after.go @@ -0,0 +1,10 @@ +package a +import ( + "fmt" + "http" +) + +func b() { + http.get("123") + fmt.Println() +} \ No newline at end of file diff --git a/testData/imports/optimize/on-the-fly/redundantImport.go b/testData/imports/optimize/on-the-fly/redundantImport.go new file mode 100644 index 0000000000..659443dad2 --- /dev/null +++ b/testData/imports/optimize/on-the-fly/redundantImport.go @@ -0,0 +1,10 @@ +package a +import ( + fmt "fmt" + "http" +) + +func b() { + http.get("123") + fmt.Println() +} \ No newline at end of file diff --git a/testData/imports/optimize/on-the-fly/unusedImport-after.go b/testData/imports/optimize/on-the-fly/unusedImport-after.go new file mode 100644 index 0000000000..ee8dcd3341 --- /dev/null +++ b/testData/imports/optimize/on-the-fly/unusedImport-after.go @@ -0,0 +1,4 @@ +package a + +func b() { +} \ No newline at end of file diff --git a/testData/imports/optimize/on-the-fly/unusedImport.go b/testData/imports/optimize/on-the-fly/unusedImport.go new file mode 100644 index 0000000000..11061ba799 --- /dev/null +++ b/testData/imports/optimize/on-the-fly/unusedImport.go @@ -0,0 +1,5 @@ +package a +import "fmt" + +func b() { +} \ No newline at end of file diff --git a/tests/com/goide/codeInsight/imports/GoOptimizeImportsOnTheFlyTest.java b/tests/com/goide/codeInsight/imports/GoOptimizeImportsOnTheFlyTest.java new file mode 100644 index 0000000000..6155a33ad1 --- /dev/null +++ b/tests/com/goide/codeInsight/imports/GoOptimizeImportsOnTheFlyTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2013-2015 Sergey Ignatov, Alexander Zolotov, Mihai Toader, Florin Patan + * + * 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 com.goide.codeInsight.imports; + +import com.goide.GoCodeInsightFixtureTestCase; +import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl; + +public class GoOptimizeImportsOnTheFlyTest extends GoCodeInsightFixtureTestCase { + @Override + public void setUp() throws Exception { + super.setUp(); + setUpProjectSdk(); + ((CodeInsightTestFixtureImpl)myFixture).canChangeDocumentDuringHighlighting(true); + GoCodeInsightSettings.getInstance().setOptimizeImportsOnTheFly(true); + } + + @Override + protected void tearDown() throws Exception { + GoCodeInsightSettings.getInstance().setOptimizeImportsOnTheFly(false); + super.tearDown(); + } + + @Override + protected String getBasePath() { + return "imports/optimize/on-the-fly"; + } + + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return createMockProjectDescriptor(); + } + + @Override + protected boolean isWriteActionRequired() { + return false; + } + + private void doTest() { + String testName = getTestName(true); + myFixture.configureByFile(testName + ".go"); + myFixture.doHighlighting(); + myFixture.checkResultByFile(testName + "-after.go"); + } + + public void testUnusedImport() { doTest(); } + public void testRedundantImport() { doTest(); } + public void testRedeclaredImport() { doTest(); } +} From 5680c659e49b176fbb7f28e62030135a8f5bd14a Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Mon, 17 Aug 2015 19:40:10 +0300 Subject: [PATCH 2/3] Enable optimize imports on the fly by default --- .../goide/codeInsight/imports/GoCodeInsightSettings.java | 2 +- .../imports/GoOptimizeImportsOnTheFlyTest.java | 2 -- tests/com/goide/inspections/GoHighlightingTest.java | 8 ++++++++ .../goide/inspections/GoTestSignaturesInspectionTest.java | 8 ++++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/com/goide/codeInsight/imports/GoCodeInsightSettings.java b/src/com/goide/codeInsight/imports/GoCodeInsightSettings.java index 041261fbab..96b3905607 100644 --- a/src/com/goide/codeInsight/imports/GoCodeInsightSettings.java +++ b/src/com/goide/codeInsight/imports/GoCodeInsightSettings.java @@ -26,7 +26,7 @@ ) public class GoCodeInsightSettings implements PersistentStateComponent { private boolean myShowImportPopup = true; - private boolean myOptimizeImportsOnTheFly = false; + private boolean myOptimizeImportsOnTheFly = true; private boolean myAddUnambiguousImportsOnTheFly = true; public static GoCodeInsightSettings getInstance() { diff --git a/tests/com/goide/codeInsight/imports/GoOptimizeImportsOnTheFlyTest.java b/tests/com/goide/codeInsight/imports/GoOptimizeImportsOnTheFlyTest.java index 6155a33ad1..11892a0496 100644 --- a/tests/com/goide/codeInsight/imports/GoOptimizeImportsOnTheFlyTest.java +++ b/tests/com/goide/codeInsight/imports/GoOptimizeImportsOnTheFlyTest.java @@ -26,12 +26,10 @@ public void setUp() throws Exception { super.setUp(); setUpProjectSdk(); ((CodeInsightTestFixtureImpl)myFixture).canChangeDocumentDuringHighlighting(true); - GoCodeInsightSettings.getInstance().setOptimizeImportsOnTheFly(true); } @Override protected void tearDown() throws Exception { - GoCodeInsightSettings.getInstance().setOptimizeImportsOnTheFly(false); super.tearDown(); } diff --git a/tests/com/goide/inspections/GoHighlightingTest.java b/tests/com/goide/inspections/GoHighlightingTest.java index 8f76fa2b50..246b37034c 100644 --- a/tests/com/goide/inspections/GoHighlightingTest.java +++ b/tests/com/goide/inspections/GoHighlightingTest.java @@ -17,6 +17,7 @@ package com.goide.inspections; import com.goide.GoCodeInsightFixtureTestCase; +import com.goide.codeInsight.imports.GoCodeInsightSettings; import com.goide.inspections.unresolved.*; import com.goide.project.GoModuleLibrariesService; import com.intellij.openapi.command.WriteCommandAction; @@ -54,6 +55,13 @@ public void setUp() throws Exception { GoTestSignaturesInspection.class, GoAssignmentNilWithoutExplicitType.class ); + GoCodeInsightSettings.getInstance().setOptimizeImportsOnTheFly(false); + } + + @Override + protected void tearDown() throws Exception { + GoCodeInsightSettings.getInstance().setOptimizeImportsOnTheFly(true); + super.tearDown(); } private void doTest() { diff --git a/tests/com/goide/inspections/GoTestSignaturesInspectionTest.java b/tests/com/goide/inspections/GoTestSignaturesInspectionTest.java index 0cd570d713..b7bc6a6229 100644 --- a/tests/com/goide/inspections/GoTestSignaturesInspectionTest.java +++ b/tests/com/goide/inspections/GoTestSignaturesInspectionTest.java @@ -16,15 +16,23 @@ package com.goide.inspections; +import com.goide.codeInsight.imports.GoCodeInsightSettings; import com.goide.quickfix.GoQuickFixTestBase; import com.intellij.testFramework.LightProjectDescriptor; public class GoTestSignaturesInspectionTest extends GoQuickFixTestBase { + @Override + protected void tearDown() throws Exception { + GoCodeInsightSettings.getInstance().setOptimizeImportsOnTheFly(true); + super.tearDown(); + } + @Override protected void setUp() throws Exception { super.setUp(); setUpProjectSdk(); myFixture.enableInspections(GoTestSignaturesInspection.class); + GoCodeInsightSettings.getInstance().setOptimizeImportsOnTheFly(false); } @Override From 3cb5af0a70b9da0311a5948fe7f79532f53efd4a Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Mon, 17 Aug 2015 20:44:43 +0300 Subject: [PATCH 3/3] Process imports in background thread --- .../codeInsight/imports/GoOptimizeImportsPass.java | 9 +++++++-- .../inspections/GoTestSignaturesInspectionTest.java | 12 ++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/com/goide/codeInsight/imports/GoOptimizeImportsPass.java b/src/com/goide/codeInsight/imports/GoOptimizeImportsPass.java index 26d33fd2b5..d7cbfd5653 100644 --- a/src/com/goide/codeInsight/imports/GoOptimizeImportsPass.java +++ b/src/com/goide/codeInsight/imports/GoOptimizeImportsPass.java @@ -18,6 +18,7 @@ import com.intellij.codeInsight.daemon.impl.DefaultHighlightInfoProcessor; import com.intellij.codeInsight.daemon.impl.ProgressableTextEditorHighlightingPass; +import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; @@ -27,6 +28,7 @@ public class GoOptimizeImportsPass extends ProgressableTextEditorHighlightingPass { @NotNull private final PsiFile myFile; + private Runnable myRunnableFix; public GoOptimizeImportsPass(@NotNull Project project, @NotNull PsiFile file, @NotNull Editor editor) { super(project, editor.getDocument(), "Go Optimize Imports Pass", file, editor, file.getTextRange(), false, @@ -36,12 +38,15 @@ public GoOptimizeImportsPass(@NotNull Project project, @NotNull PsiFile file, @N @Override protected void collectInformationWithProgress(@NotNull ProgressIndicator progress) { + myRunnableFix = new GoImportOptimizer().processFile(myFile); progress.checkCanceled(); } @Override protected void applyInformationWithProgress() { - final Runnable runnable = new GoImportOptimizer().processFile(myFile); - DocumentUtil.writeInRunUndoTransparentAction(runnable); + final Project project = myFile.getProject(); + UndoManager undoManager = UndoManager.getInstance(project); + if (undoManager.isUndoInProgress() || undoManager.isRedoInProgress()) return; + DocumentUtil.writeInRunUndoTransparentAction(myRunnableFix); } } diff --git a/tests/com/goide/inspections/GoTestSignaturesInspectionTest.java b/tests/com/goide/inspections/GoTestSignaturesInspectionTest.java index b7bc6a6229..6b2b03f0a8 100644 --- a/tests/com/goide/inspections/GoTestSignaturesInspectionTest.java +++ b/tests/com/goide/inspections/GoTestSignaturesInspectionTest.java @@ -21,12 +21,6 @@ import com.intellij.testFramework.LightProjectDescriptor; public class GoTestSignaturesInspectionTest extends GoQuickFixTestBase { - @Override - protected void tearDown() throws Exception { - GoCodeInsightSettings.getInstance().setOptimizeImportsOnTheFly(true); - super.tearDown(); - } - @Override protected void setUp() throws Exception { super.setUp(); @@ -35,6 +29,12 @@ protected void setUp() throws Exception { GoCodeInsightSettings.getInstance().setOptimizeImportsOnTheFly(false); } + @Override + protected void tearDown() throws Exception { + GoCodeInsightSettings.getInstance().setOptimizeImportsOnTheFly(true); + super.tearDown(); + } + @Override protected LightProjectDescriptor getProjectDescriptor() { return createMockProjectDescriptor();