From 8ea1caf8b82c0021e5787ad63c6e7d0372935ce9 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 12 Sep 2016 12:47:34 +0300 Subject: [PATCH 01/24] ignore rulesChanged event for hidden usage view tabs to fix IDEA-140429 10s hang on changing groupping in show usages --- .../intellij/usages/impl/UsageViewImpl.java | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java b/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java index 537f40e33475..7f7f1ca3facf 100644 --- a/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java +++ b/platform/usageView/src/com/intellij/usages/impl/UsageViewImpl.java @@ -248,6 +248,16 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra }); } }); + + myTree.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + if (rulesChanged) { + rulesChanged = false; + rulesChanged(); + } + } + }); } }); } @@ -292,12 +302,12 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra }; } - protected boolean searchHasBeenCancelled() { + boolean searchHasBeenCancelled() { ProgressIndicator progress = associatedProgress; return progress != null && progress.isCanceled(); } - protected void cancelCurrentSearch() { + void cancelCurrentSearch() { ProgressIndicator progress = associatedProgress; if (progress != null) { ProgressWrapper.unwrap(progress).cancel(); @@ -704,8 +714,18 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra return list.toArray(new AnAction[list.size()]); } + private boolean shouldTreeReactNowToRuleChanges() { + return myPresentation.isDetachedMode() || myTree.isShowing(); + } + + private boolean rulesChanged; private void rulesChanged() { ApplicationManager.getApplication().assertIsDispatchThread(); + if (!shouldTreeReactNowToRuleChanges()) { + rulesChanged = true; + return; + } + final List states = new ArrayList<>(); captureUsagesExpandState(new TreePath(myTree.getModel().getRoot()), states); final List allUsages = new ArrayList<>(myUsageNodes.keySet()); @@ -786,7 +806,7 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra TreeUtil.expand(myTree, 2); } - public DefaultMutableTreeNode getModelRoot() { + DefaultMutableTreeNode getModelRoot() { return (DefaultMutableTreeNode)myTree.getModel().getRoot(); } @@ -910,12 +930,7 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra private final TransferToEDTQueue myTransferToEDTQueue; void drainQueuedUsageNodes() { assert !ApplicationManager.getApplication().isDispatchThread() : Thread.currentThread(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - myTransferToEDTQueue.drain(); - } - }); + UIUtil.invokeAndWaitIfNeeded((Runnable)myTransferToEDTQueue::drain); } private final Consumer edtQueue = new Consumer() { @Override @@ -1233,9 +1248,10 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra addButtonToLowerPane(newPerformOperationRunnable(processRunnable, commandName, cannotMakeString, checkReadOnlyStatus), shortDescription); } - public MyPerformOperationRunnable newPerformOperationRunnable(Runnable processRunnable, - String commandName, - String cannotMakeString, boolean checkReadOnlyStatus) { + @NotNull + private MyPerformOperationRunnable newPerformOperationRunnable(Runnable processRunnable, + String commandName, + String cannotMakeString, boolean checkReadOnlyStatus) { return new MyPerformOperationRunnable(cannotMakeString, processRunnable, commandName, checkReadOnlyStatus); } @@ -1443,7 +1459,7 @@ public class UsageViewImpl implements UsageView, UsageModelTracker.UsageModelTra return result.toArray(new Navigatable[result.size()]); } - public boolean areTargetsValid() { + boolean areTargetsValid() { return myModel.areTargetsValid(); } From 5813976925ea393c713a35a7f0293a828776af93 Mon Sep 17 00:00:00 2001 From: Pavel Dolgov Date: Mon, 12 Sep 2016 13:00:48 +0300 Subject: [PATCH 02/24] Javafx: Don't show number format error for resource keys (IDEA-160452) --- .../plugins/javaFX/fxml/JavaFXHighlightingTest.java | 4 ++++ .../JavaFxPropertyAttributeDescriptor.java | 3 +++ .../highlighting/resourceIdInFxAttribute.fxml | 12 ++++++++++++ 3 files changed, 19 insertions(+) create mode 100644 plugins/javaFX/testData/highlighting/resourceIdInFxAttribute.fxml diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java index 2e77d3f94017..fc82a64c504d 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java @@ -490,6 +490,10 @@ public class JavaFXHighlightingTest extends AbstractJavaFXTestCase { myFixture.testHighlighting(true, true, true, superclass + ".java"); } + public void testResourceIdInFxAttribute() throws Exception { + doTest(); + } + private void doTest() throws Exception { myFixture.testHighlighting(false, false, false, getTestName(true) + ".fxml"); } diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyAttributeDescriptor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyAttributeDescriptor.java index fed43233a544..ebda3a2ed49a 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyAttributeDescriptor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyAttributeDescriptor.java @@ -133,6 +133,9 @@ public class JavaFxPropertyAttributeDescriptor extends BasicXmlAttributeDescript else if (StringUtil.trimLeading(value).startsWith("$")) { return "Spaces aren't allowed before property or expression"; } + else if (value.startsWith("%")) { + return null; + } else { return validateLiteral(xmlAttributeValue, value); } diff --git a/plugins/javaFX/testData/highlighting/resourceIdInFxAttribute.fxml b/plugins/javaFX/testData/highlighting/resourceIdInFxAttribute.fxml new file mode 100644 index 000000000000..96dfc950f2be --- /dev/null +++ b/plugins/javaFX/testData/highlighting/resourceIdInFxAttribute.fxml @@ -0,0 +1,12 @@ + + + + + + + + "%double.key"/> + + + \ No newline at end of file From 34ed877b9dee29b06487bd10438ba9d1abd84886 Mon Sep 17 00:00:00 2001 From: nik Date: Mon, 12 Sep 2016 13:42:03 +0300 Subject: [PATCH 03/24] build scripts tests: makeAll/rebuildAll methods deprecated --- .../jps/builders/CompileScopeTestBuilder.java | 5 ++++ .../jps/builders/JpsBuildTestCase.java | 17 +++++++++++ .../jps/builders/java/ClassMoveTest.java | 6 ++-- .../java/ClassesWithMultipleSourcesTest.kt | 4 +-- .../java/DependentModulesCompilationTest.java | 6 ++-- .../builders/java/ForcedCompilationTest.java | 10 +++---- .../builders/rebuild/JpsRebuildTestCase.kt | 3 +- .../resources/ResourceCopyingTest.java | 10 +++---- .../artifacts/ArtifactBuilderTest.java | 6 ++-- .../artifacts/ArtifactBuilderTestCase.java | 10 +++++++ .../CleanArtifactOutputOnRebuildTest.java | 12 ++++---- .../IncrementalArtifactBuildingTest.java | 4 +-- .../ant/JpsAntArtifactBuilderTaskTest.java | 2 +- .../AppEngineEnhancerBuilderTest.java | 8 ++--- .../maven/model/JpsMavenJavaBuildingTest.java | 2 +- .../uiDesigner/build/FormsBuilderTest.java | 30 +++++++++---------- 16 files changed, 84 insertions(+), 51 deletions(-) diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/CompileScopeTestBuilder.java b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/CompileScopeTestBuilder.java index 0999398a2dfb..50c51e9a7c10 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/CompileScopeTestBuilder.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/CompileScopeTestBuilder.java @@ -107,6 +107,11 @@ public class CompileScopeTestBuilder { return new CompileScopeImpl(myTargetTypes, typesToForceBuild, myTargets, myFiles); } + /** + * Add all targets in the project to the scope. May lead to unpredictable results if some plugins add targets your test doesn't expect. + * + * @deprecated use {@link #allModules()} instead or directly add required target types via {@link #targetTypes} + */ public CompileScopeTestBuilder all() { myTargetTypes.addAll(TargetTypeRegistry.getInstance().getTargetTypes()); return this; diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java index 3df2c5df90b7..e0c6ccc77601 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/JpsBuildTestCase.java @@ -279,10 +279,27 @@ public abstract class JpsBuildTestCase extends UsefulTestCase { return module; } + protected void rebuildAllModules() { + doBuild(CompileScopeTestBuilder.rebuild().allModules()).assertSuccessful(); + } + + /** + * Invoked forced rebuild for all targets in the project. May lead to unpredictable results if some plugins add targets your test doesn't expect. + * @deprecated use {@link #rebuildAllModules()} instead or directly add required target types to the scope via {@link CompileScopeTestBuilder#targetTypes} + */ protected void rebuildAll() { doBuild(CompileScopeTestBuilder.rebuild().all()).assertSuccessful(); } + protected BuildResult buildAllModules() { + return doBuild(make().allModules()); + } + + /** + * Invoked incremental build for all targets in the project. May lead to unpredictable results if some plugins add targets your test doesn't expect. + * + * @deprecated use {@link #buildAllModules()} instead or directly add required target types to the scope via {@link CompileScopeTestBuilder#targetTypes} + */ protected BuildResult makeAll() { return doBuild(make().all()); } diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/ClassMoveTest.java b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/ClassMoveTest.java index 5fbcb0d6ee49..3bfeca2ccd65 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/ClassMoveTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/ClassMoveTest.java @@ -29,16 +29,16 @@ public class ClassMoveTest extends JpsBuildTestCase { String a1 = createFile("src1/A.java", "class A{}"); String b = createFile("src2/B.java", "class B{}"); JpsModule m = addModule("m", PathUtil.getParentPath(a1), PathUtil.getParentPath(b)); - makeAll(); + buildAllModules(); assertOutput(m, fs().file("A.class").file("B.class")); delete(a1); String a2 = createFile("src2/A.java", "class A{}"); - makeAll(); + buildAllModules(); assertOutput(m, fs().file("A.class").file("B.class")); delete(a2); - makeAll(); + buildAllModules(); assertOutput(m, fs().file("B.class")); } } diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/ClassesWithMultipleSourcesTest.kt b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/ClassesWithMultipleSourcesTest.kt index 2e57fbead7ec..a3b02ce2b0bb 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/ClassesWithMultipleSourcesTest.kt +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/ClassesWithMultipleSourcesTest.kt @@ -85,11 +85,11 @@ class ClassesWithMultipleSourcesTest: JpsBuildTestCase() { addModule("m", createDir("src")) val testActions = BuildTestActions() testActions.actions() - rebuildAll() + rebuildAllModules() var result: BuildResult? = null testActions.modifyActions.forEach { action -> action() - result = makeAll() + result = buildAllModules() result!!.assertSuccessful() } checkLog() diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/DependentModulesCompilationTest.java b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/DependentModulesCompilationTest.java index fc1ed4c9490f..de9fa9226c3c 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/DependentModulesCompilationTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/DependentModulesCompilationTest.java @@ -33,7 +33,7 @@ public class DependentModulesCompilationTest extends JpsBuildTestCase { JpsModule main = addModule("main", mainRoot); JpsModule dep = addModule("dep", depRoot); main.getDependenciesList().addModuleDependency(dep); - rebuildAll(); + rebuildAllModules(); } public void testTestOnProductionDependency() { @@ -43,7 +43,7 @@ public class DependentModulesCompilationTest extends JpsBuildTestCase { main.addSourceRoot(JpsPathUtil.pathToUrl(testRoot), JavaSourceRootType.TEST_SOURCE); JpsModule dep = addModule("dep", depRoot); main.getDependenciesList().addModuleDependency(dep); - rebuildAll(); + rebuildAllModules(); } public void testTransitiveDependencyViaDummyModule() { @@ -58,7 +58,7 @@ public class DependentModulesCompilationTest extends JpsBuildTestCase { addExportedDependency(dummy, dummy2); addExportedDependency(dummy2, dep); dummy2.getDependenciesList().addModuleDependency(dummy); - rebuildAll(); + rebuildAllModules(); } private static void addExportedDependency(JpsModule main, JpsModule dep) { diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/ForcedCompilationTest.java b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/ForcedCompilationTest.java index 79ae0b9febdc..a34885cae346 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/ForcedCompilationTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/java/ForcedCompilationTest.java @@ -34,7 +34,7 @@ public class ForcedCompilationTest extends JpsBuildTestCase { JpsModule main = addModule("main", srcRoot); JpsModule dep = addModule("dep", PathUtil.getParentPath(b)); main.getDependenciesList().addModuleDependency(dep); - rebuildAll(); + rebuildAllModules(); change(b, "public class B{ public B(int i){} }"); doBuild(CompileScopeTestBuilder.recompile().module(dep)).assertSuccessful(); @@ -44,10 +44,10 @@ public class ForcedCompilationTest extends JpsBuildTestCase { public void testClearModuleOutputOnForcedCompilation() { String srcRoot = PathUtil.getParentPath(createFile("src/A.java", "class A{ }")); JpsModule main = addModule("main", srcRoot); - rebuildAll(); + rebuildAllModules(); File b = new File(createFile(getModuleOutputRelativePath(main) + "/a.txt", "qwerty")); - makeAll(); + buildAllModules(); assertExists(b); doBuild(CompileScopeTestBuilder.recompile().module(main)).assertSuccessful(); @@ -61,10 +61,10 @@ public class ForcedCompilationTest extends JpsBuildTestCase { JpsJavaModuleExtension m2Ext = JpsJavaExtensionService.getInstance().getOrCreateModuleExtension(m2); m2Ext.setOutputUrl(m1Ext.getOutputUrl()); m2Ext.setTestOutputUrl(m1Ext.getOutputUrl()); - rebuildAll(); + rebuildAllModules(); File b = new File(createFile(getModuleOutputRelativePath(m1) + "/a.txt", "qwerty")); - makeAll(); + buildAllModules(); assertExists(b); assertExists(new File(getOrCreateProjectDir(), getModuleOutputRelativePath(m1) + "/A.class")); assertExists(new File(getOrCreateProjectDir(), getModuleOutputRelativePath(m1) + "/B.class")); diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/rebuild/JpsRebuildTestCase.kt b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/rebuild/JpsRebuildTestCase.kt index 3a8d58fc29ac..c5f31e4e988b 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/rebuild/JpsRebuildTestCase.kt +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/rebuild/JpsRebuildTestCase.kt @@ -19,6 +19,7 @@ import com.intellij.openapi.application.ex.PathManagerEx import com.intellij.openapi.util.io.FileUtil import com.intellij.util.io.TestFileSystemBuilder import com.intellij.util.io.TestFileSystemItem +import org.jetbrains.jps.builders.CompileScopeTestBuilder import org.jetbrains.jps.builders.JpsBuildTestCase import org.jetbrains.jps.model.java.JpsJavaExtensionService import org.jetbrains.jps.util.JpsPathUtil @@ -58,7 +59,7 @@ abstract class JpsRebuildTestCase: JpsBuildTestCase() { fun rebuild() { JpsJavaExtensionService.getInstance()!!.getOrCreateProjectExtension(myProject).outputUrl = JpsPathUtil.pathToUrl(FileUtil.toSystemIndependentName(myOutputDirectory.absolutePath)); - rebuildAll(); + doBuild(CompileScopeTestBuilder.rebuild().allModules().allArtifacts()).assertSuccessful() } override fun getAdditionalPathVariables(): MutableMap = diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/resources/ResourceCopyingTest.java b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/resources/ResourceCopyingTest.java index d2ad9f1f71c5..d5904fc8035f 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/builders/resources/ResourceCopyingTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/builders/resources/ResourceCopyingTest.java @@ -41,17 +41,17 @@ public class ResourceCopyingTest extends JpsBuildTestCase { public void testSimple() { String file = createFile("src/a.xml"); JpsModule m = addModule("m", PathUtil.getParentPath(file)); - rebuildAll(); + rebuildAllModules(); assertOutput(m, fs().file("a.xml")); } public void testCaseChange() { String file = createFile("src/a.xml"); JpsModule m = addModule("m", PathUtil.getParentPath(file)); - rebuildAll(); + rebuildAllModules(); assertOutput(m, fs().file("a.xml")); rename(file, "A.xml"); - makeAll(); + buildAllModules(); assertOutput(m, fs().file("A.xml")); } @@ -62,7 +62,7 @@ public class ResourceCopyingTest extends JpsBuildTestCase { JpsTypedModuleSourceRoot typed = sourceRoot.asTyped(JavaSourceRootType.SOURCE); assertNotNull(typed); typed.getProperties().setPackagePrefix("xxx"); - rebuildAll(); + rebuildAllModules(); assertOutput(m, fs().dir("xxx").file("a.xml")); } @@ -70,7 +70,7 @@ public class ResourceCopyingTest extends JpsBuildTestCase { String file = createFile("res/A.java", "xxx"); JpsModule m = addModule("m"); m.addSourceRoot(JpsPathUtil.pathToUrl(PathUtil.getParentPath(file)), JavaResourceRootType.RESOURCE); - rebuildAll(); + rebuildAllModules(); assertOutput(m, fs().file("A.java", "xxx")); } } diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTest.java b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTest.java index 3c0d5a5796b4..5507efaeee22 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTest.java @@ -354,7 +354,7 @@ public class ArtifactBuilderTest extends ArtifactBuilderTestCase { JpsModule module = addModule("m", src); File output = JpsJavaExtensionService.getInstance().getOutputDirectory(module, false); JpsArtifact artifact = addArtifact(root().dirCopy(new File(output, "x").getAbsolutePath())); - rebuildAll(); + rebuildAllModulesAndArtifacts(); assertOutput(module, fs().dir("x").file("A.class")); assertOutput(artifact, fs().file("A.class")); } @@ -367,7 +367,7 @@ public class ArtifactBuilderTest extends ArtifactBuilderTestCase { buildAllAndAssertUpToDate(); assertOutput(a, fs().file("a.txt").file("b.txt")); - rebuildAll(); + rebuildAllModulesAndArtifacts(); assertOutput(a, fs().file("a.txt")); } @@ -379,7 +379,7 @@ public class ArtifactBuilderTest extends ArtifactBuilderTestCase { buildAllAndAssertUpToDate(); assertOutput(a, fs().archive("a.jar").file("a.txt").end().file("b.txt")); - rebuildAll(); + rebuildAllModulesAndArtifacts(); assertOutput(a, fs().archive("a.jar").file("a.txt").end().file("b.txt")); } diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java index cec29770ba23..d4d0f259b549 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTestCase.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.io.TestFileSystemBuilder; import com.intellij.util.text.UniqueNameGenerator; +import org.jetbrains.jps.builders.BuildResult; import org.jetbrains.jps.builders.CompileScopeTestBuilder; import org.jetbrains.jps.builders.JpsBuildTestCase; import org.jetbrains.jps.model.JpsElementFactory; @@ -40,6 +41,7 @@ import java.util.HashSet; import java.util.Set; import static com.intellij.util.io.TestFileSystemItem.fs; +import static org.jetbrains.jps.builders.CompileScopeTestBuilder.make; /** * @author nik @@ -113,6 +115,14 @@ public abstract class ArtifactBuilderTestCase extends JpsBuildTestCase { doBuild(CompileScopeTestBuilder.make().allModules().artifacts(artifacts)).assertSuccessful(); } + protected void rebuildAllModulesAndArtifacts() { + doBuild(CompileScopeTestBuilder.rebuild().allModules().allArtifacts()).assertSuccessful(); + } + + protected BuildResult buildAllModulesAndArtifacts() { + return doBuild(make().allModules().allArtifacts()); + } + protected static String getJUnitJarPath() { final File file = PathManager.findFileInLibDirectory("junit.jar"); assertTrue("File " + file.getAbsolutePath() + " doesn't exist", file.exists()); diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/CleanArtifactOutputOnRebuildTest.java b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/CleanArtifactOutputOnRebuildTest.java index b03243b80f30..663d29275dba 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/CleanArtifactOutputOnRebuildTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/CleanArtifactOutputOnRebuildTest.java @@ -35,7 +35,7 @@ public class CleanArtifactOutputOnRebuildTest extends ArtifactBuilderTestCase { createFileInArtifactOutput(a, "b.txt"); assertOutput(a, fs().file("a.txt").file("b.txt")); - rebuildAll(); + rebuildAllModulesAndArtifacts(); assertOutput(a, fs().file("a.txt")); } @@ -44,7 +44,7 @@ public class CleanArtifactOutputOnRebuildTest extends ArtifactBuilderTestCase { JpsArtifact a = addArtifact(root().fileCopy(createFile("a.txt"))); buildArtifacts(a); createFileInArtifactOutput(a, "b.txt"); - rebuildAll(); + rebuildAllModulesAndArtifacts(); assertOutput(a, fs().file("a.txt").file("b.txt")); } @@ -53,7 +53,7 @@ public class CleanArtifactOutputOnRebuildTest extends ArtifactBuilderTestCase { addModule("m", a.getOutputPath() + "/src"); buildArtifacts(a); createFileInArtifactOutput(a, "b.txt"); - rebuildAll(); + rebuildAllModulesAndArtifacts(); assertOutput(a, fs().file("a.txt").file("b.txt")); } @@ -67,7 +67,7 @@ public class CleanArtifactOutputOnRebuildTest extends ArtifactBuilderTestCase { assertOutput(a, fs().file("a.txt")); createFile("res/b.txt"); - rebuildAll(); + rebuildAllModulesAndArtifacts(); assertOutput(a, fs().file("a.txt").file("b.txt")); } @@ -77,7 +77,7 @@ public class CleanArtifactOutputOnRebuildTest extends ArtifactBuilderTestCase { buildArtifacts(a, included); createFileInArtifactOutput(included, "b.txt"); assertOutput(included, fs().file("a.txt").file("b.txt")); - rebuildAll(); + rebuildAllModulesAndArtifacts(); assertOutput(included, fs().file("a.txt")); } @@ -89,7 +89,7 @@ public class CleanArtifactOutputOnRebuildTest extends ArtifactBuilderTestCase { createFileInModuleOutput(m, "b.txt"); assertOutput(m, fs().file("A.class").file("b.txt")); - rebuildAll(); + rebuildAllModulesAndArtifacts(); assertOutput(m, fs().file("A.class")); } } diff --git a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/IncrementalArtifactBuildingTest.java b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/IncrementalArtifactBuildingTest.java index a3c2594f3534..cefb3344d9d1 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/IncrementalArtifactBuildingTest.java +++ b/jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/IncrementalArtifactBuildingTest.java @@ -222,7 +222,7 @@ public class IncrementalArtifactBuildingTest extends ArtifactBuilderTestCase { createFile("d/2.txt"); JpsArtifact included = addArtifact("i", root().parentDirCopy(file1)); JpsArtifact a = addArtifact(root().artifact(included)); - makeAll(); + buildAllModulesAndArtifacts(); assertOutput(included, fs().file("1.txt").file("2.txt")); assertOutput(a, fs().file("1.txt").file("2.txt")); @@ -233,7 +233,7 @@ public class IncrementalArtifactBuildingTest extends ArtifactBuilderTestCase { assertOutput(included, fs().file("2.txt")); assertOutput(a, fs().file("1.txt").file("2.txt")); - makeAll(); + buildAllModulesAndArtifacts(); assertOutput(a, fs().file("2.txt")); } diff --git a/plugins/ant/jps-plugin/testSrc/org/jetbrains/jps/ant/JpsAntArtifactBuilderTaskTest.java b/plugins/ant/jps-plugin/testSrc/org/jetbrains/jps/ant/JpsAntArtifactBuilderTaskTest.java index baff66317278..1dca91737362 100644 --- a/plugins/ant/jps-plugin/testSrc/org/jetbrains/jps/ant/JpsAntArtifactBuilderTaskTest.java +++ b/plugins/ant/jps-plugin/testSrc/org/jetbrains/jps/ant/JpsAntArtifactBuilderTaskTest.java @@ -49,7 +49,7 @@ public class JpsAntArtifactBuilderTaskTest extends ArtifactBuilderTestCase { JpsGlobalLoader.loadGlobalSettings(myModel.getGlobal(), getTestDataRootPath() + "/config/options"); addJdk("1.6"); loadProject("ant-project"); - rebuildAll(); + rebuildAllModulesAndArtifacts(); assertOutput(new File(myArtifactsOutput, "dir").getAbsolutePath(), fs().file("file.txt").file("echo.txt", "post")); diff --git a/plugins/google-app-engine/jps-plugin/testSource/org/jetbrains/jps/appengine/AppEngineEnhancerBuilderTest.java b/plugins/google-app-engine/jps-plugin/testSource/org/jetbrains/jps/appengine/AppEngineEnhancerBuilderTest.java index 7f75d64f9130..507a3c52a7b9 100644 --- a/plugins/google-app-engine/jps-plugin/testSource/org/jetbrains/jps/appengine/AppEngineEnhancerBuilderTest.java +++ b/plugins/google-app-engine/jps-plugin/testSource/org/jetbrains/jps/appengine/AppEngineEnhancerBuilderTest.java @@ -37,21 +37,21 @@ public class AppEngineEnhancerBuilderTest extends JpsBuildTestCase { public void testChangeFile() { String file = createFile("src/A.java", "class A{}"); addAppEngineModule("a", true, PathUtil.getParentPath(file)); - makeAll(); + buildAllModules(); assertEnhanced("out/production/a/A.class"); - makeAll(); + buildAllModules(); assertEnhanced(); change(file); - makeAll(); + buildAllModules(); assertEnhanced("out/production/a/A.class"); } public void testDoNotRunEnhancerIfDisabled() { String file = createFile("src/A.java", "class A{}"); addAppEngineModule("a", false, PathUtil.getParentPath(file)); - makeAll(); + buildAllModules(); assertEnhanced(); } diff --git a/plugins/maven/jps-plugin/testSrc/org/jetbrains/jps/maven/model/JpsMavenJavaBuildingTest.java b/plugins/maven/jps-plugin/testSrc/org/jetbrains/jps/maven/model/JpsMavenJavaBuildingTest.java index 1f79f307f50a..39326d9280a3 100644 --- a/plugins/maven/jps-plugin/testSrc/org/jetbrains/jps/maven/model/JpsMavenJavaBuildingTest.java +++ b/plugins/maven/jps-plugin/testSrc/org/jetbrains/jps/maven/model/JpsMavenJavaBuildingTest.java @@ -35,7 +35,7 @@ public class JpsMavenJavaBuildingTest extends JpsBuildTestCase { FileUtil.copyDir(srcDir, workDir); addJdk("1.6"); loadProject(workDir.getAbsolutePath()); - BuildResult result = doBuild(CompileScopeTestBuilder.rebuild().all()); + BuildResult result = doBuild(CompileScopeTestBuilder.rebuild().allModules()); result.assertFailed(); BuildMessage message = assertOneElement(result.getMessages(BuildMessage.Kind.ERROR)); assertTrue(message.toString(), message.getMessageText().contains("Maven project configuration") && message.getMessageText().contains("isn't available.")); diff --git a/plugins/ui-designer/jps-plugin/testSrc/org/jetbrains/jps/uiDesigner/build/FormsBuilderTest.java b/plugins/ui-designer/jps-plugin/testSrc/org/jetbrains/jps/uiDesigner/build/FormsBuilderTest.java index 10611778efa5..0b90de86c416 100644 --- a/plugins/ui-designer/jps-plugin/testSrc/org/jetbrains/jps/uiDesigner/build/FormsBuilderTest.java +++ b/plugins/ui-designer/jps-plugin/testSrc/org/jetbrains/jps/uiDesigner/build/FormsBuilderTest.java @@ -41,51 +41,51 @@ public class FormsBuilderTest extends JpsBuildTestCase { public void testSimple() { JpsModule m = addModule("m", copyToProject(SIMPLE_FORM_PATH, "src")); - makeAll().assertSuccessful(); + buildAllModules().assertSuccessful(); assertTrue(isRuntimeClassesCopied(m)); assertInstrumented(m, "xxx/MyForm.class"); - makeAll().assertUpToDate(); + buildAllModules().assertUpToDate(); } public void testEnableInstrumenting() { JpsModule m = addModule("m", copyToProject(SIMPLE_FORM_PATH, "src")); JpsUiDesignerExtensionService.getInstance().getOrCreateUiDesignerConfiguration(myProject).setInstrumentClasses(false); - makeAll().assertSuccessful(); + buildAllModules().assertSuccessful(); assertNotInstrumented(m, "xxx/MyForm.class"); - makeAll().assertUpToDate(); + buildAllModules().assertUpToDate(); JpsUiDesignerExtensionService.getInstance().getOrCreateUiDesignerConfiguration(myProject).setInstrumentClasses(true); - makeAll().assertSuccessful(); + buildAllModules().assertSuccessful(); assertInstrumented(m, "xxx/MyForm.class"); - makeAll().assertUpToDate(); + buildAllModules().assertUpToDate(); } public void testDisableInstrumenting() { JpsModule m = addModule("m", copyToProject(SIMPLE_FORM_PATH, "src")); - makeAll().assertSuccessful(); + buildAllModules().assertSuccessful(); assertInstrumented(m, "xxx/MyForm.class"); JpsUiDesignerExtensionService.getInstance().getOrCreateUiDesignerConfiguration(myProject).setInstrumentClasses(false); - rebuildAll();//todo[nik,jeka] perhaps we shouldn't require rebuild to remove instrumented code + rebuildAllModules();//todo[nik,jeka] perhaps we shouldn't require rebuild to remove instrumented code assertNotInstrumented(m, "xxx/MyForm.class"); } public void testRecompileFormForChangedClass() { JpsModule m = addModule("m", copyToProject(SIMPLE_FORM_PATH, "src")); - makeAll().assertSuccessful(); + buildAllModules().assertSuccessful(); assertInstrumented(m, "xxx/MyForm.class"); change(getAbsolutePath("src/xxx/MyForm.java")); - makeAll().assertSuccessful(); + buildAllModules().assertSuccessful(); assertCompiled(JavaBuilder.BUILDER_NAME, "src/xxx/MyForm.java"); assertCompiled(FormsInstrumenter.BUILDER_NAME, "src/xxx/MyForm.form"); assertInstrumented(m, "xxx/MyForm.class"); - makeAll().assertUpToDate(); + buildAllModules().assertUpToDate(); } public void testRecompileFormForChangedClassOnSecondCompilationRound() { JpsModule m = addModule("m", copyToProject(SIMPLE_FORM_PATH, "src")); - makeAll().assertSuccessful(); + buildAllModules().assertSuccessful(); assertInstrumented(m, "xxx/MyForm.class"); change(getAbsolutePath("src/xxx/Constants.java"), "package xxx;\n" + @@ -93,16 +93,16 @@ public class FormsBuilderTest extends JpsBuildTestCase { "public class Constants {\n" + " public static int CONST = 10;\n" + "}"); - makeAll().assertSuccessful(); + buildAllModules().assertSuccessful(); assertCompiled(JavaBuilder.BUILDER_NAME, "src/xxx/MyForm.java", "src/xxx/Constants.java"); assertCompiled(FormsInstrumenter.BUILDER_NAME, "src/xxx/MyForm.form"); assertInstrumented(m, "xxx/MyForm.class"); - makeAll().assertUpToDate(); + buildAllModules().assertUpToDate(); } public void testDoNotCopyRuntimeClassesIfOnlyAlienFormFilesExist() { JpsModule module = addModule("m", copyToProject("plugins/ui-designer/jps-plugin/testData/build/alienFormFile", "src")); - makeAll().assertSuccessful(); + buildAllModules().assertSuccessful(); assertFalse(isRuntimeClassesCopied(module)); } From dc37f19e2b79a9935eddc1a6d72adf486f4d04e1 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Mon, 12 Sep 2016 17:48:47 +0700 Subject: [PATCH 04/24] IDEA-161007 Add new inspection to make comparator lambdas use Comparator.comparing() combinators (Currently only simple comparators supported) --- .../ComparatorCombinatorsInspection.java | 123 ++++++++++++++++++ .../ConvertCompareToToEqualsIntention.java | 36 +---- .../com/intellij/psi/util/PsiMethodUtil.java | 35 ++++- .../comparatorCombinators/afterSimple.java | 14 ++ .../comparatorCombinators/beforeInverted.java | 13 ++ .../comparatorCombinators/beforeSimple.java | 13 ++ .../ComparatorCombinatorsInspectionTest.java | 38 ++++++ .../ComparatorCombinators.html | 10 ++ resources/src/META-INF/IdeaPlugin.xml | 4 + 9 files changed, 252 insertions(+), 34 deletions(-) create mode 100644 java/java-analysis-impl/src/com/intellij/codeInspection/ComparatorCombinatorsInspection.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators/afterSimple.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators/beforeInverted.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators/beforeSimple.java create mode 100644 java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ComparatorCombinatorsInspectionTest.java create mode 100644 resources-en/src/inspectionDescriptions/ComparatorCombinators.html diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/ComparatorCombinatorsInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/ComparatorCombinatorsInspection.java new file mode 100644 index 000000000000..f73513ce19f8 --- /dev/null +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/ComparatorCombinatorsInspection.java @@ -0,0 +1,123 @@ +/* + * Copyright 2000-2016 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 com.intellij.codeInspection; + +import com.intellij.codeInsight.FileModificationService; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.util.PsiMethodUtil; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +public class ComparatorCombinatorsInspection extends BaseJavaBatchLocalInspectionTool { + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { + return new JavaElementVisitor() { + @Override + public void visitLambdaExpression(PsiLambdaExpression lambda) { + super.visitLambdaExpression(lambda); + PsiType type = lambda.getFunctionalInterfaceType(); + if(type instanceof PsiClassType && ((PsiClassType)type).rawType().equalsToText(CommonClassNames.JAVA_UTIL_COMPARATOR)) { + PsiElement body = lambda.getBody(); + if(body instanceof PsiMethodCallExpression) { + PsiMethodCallExpression methodCall = (PsiMethodCallExpression)body; + if(PsiMethodUtil.isCompareToCall(methodCall)) { + PsiExpression left = methodCall.getMethodExpression().getQualifierExpression(); + PsiExpression right = methodCall.getArgumentList().getExpressions()[0]; + if(left instanceof PsiMethodCallExpression && right instanceof PsiMethodCallExpression) { + PsiMethodCallExpression leftCall = (PsiMethodCallExpression)left; + PsiMethodCallExpression rightCall = (PsiMethodCallExpression)right; + if(leftCall.getArgumentList().getExpressions().length == 0 && + rightCall.getArgumentList().getExpressions().length == 0) { + PsiMethod leftMethod = leftCall.resolveMethod(); + PsiMethod rightMethod = rightCall.resolveMethod(); + if(leftMethod != null && rightMethod != null && leftMethod == rightMethod) { + if (areLambdaParameters(lambda, leftCall.getMethodExpression().getQualifierExpression(), + rightCall.getMethodExpression().getQualifierExpression())) { + //noinspection DialogTitleCapitalization + holder.registerProblem(lambda, "Can be replaced with Comparator.comparing", new ReplaceWithComparatorFix()); + } + } + } + } + } + } + } + } + }; + } + + private static boolean areLambdaParameters(PsiLambdaExpression lambda, PsiExpression left, PsiExpression right) { + PsiParameter[] parameters = lambda.getParameterList().getParameters(); + return left instanceof PsiReferenceExpression && + right instanceof PsiReferenceExpression && + ((PsiReferenceExpression)left).resolve() == parameters[0] && + ((PsiReferenceExpression)right).resolve() == parameters[1]; + } + + @Nls + @NotNull + @Override + public String getDisplayName() { + return "Use Comparator combinators"; + } + + static class ReplaceWithComparatorFix implements LocalQuickFix { + + @Nls + @NotNull + @Override + public String getName() { + return getFamilyName(); + } + + @Nls + @NotNull + @Override + public String getFamilyName() { + return "Replace with Comparator.comparing"; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PsiElement element = descriptor.getStartElement(); + if (!(element instanceof PsiLambdaExpression)) return; + PsiLambdaExpression lambda = (PsiLambdaExpression)element; + PsiElement body = lambda.getBody(); + if (!(body instanceof PsiMethodCallExpression)) return; + PsiMethodCallExpression methodCall = (PsiMethodCallExpression)body; + if (!PsiMethodUtil.isCompareToCall(methodCall)) return; + PsiExpression qualifier = methodCall.getMethodExpression().getQualifierExpression(); + if (!(qualifier instanceof PsiMethodCallExpression)) return; + PsiMethodCallExpression call = (PsiMethodCallExpression)qualifier; + if (call.getArgumentList().getExpressions().length != 0) return; + PsiMethod method = call.resolveMethod(); + if (method == null) return; + PsiClass methodClass = method.getContainingClass(); + if (methodClass == null) return; + if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return; + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + PsiExpression replacement = + factory.createExpressionFromText("java.util.Comparator.comparing(" + methodClass.getQualifiedName() + "::" + method.getName() + ")", + element); + PsiElement result = lambda.replace(replacement); + CodeStyleManager.getInstance(project).reformat(JavaCodeStyleManager.getInstance(project).shortenClassReferences(result)); + } + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ConvertCompareToToEqualsIntention.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ConvertCompareToToEqualsIntention.java index 88cd821cd19c..f81bfcd5684f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/ConvertCompareToToEqualsIntention.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/ConvertCompareToToEqualsIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -22,7 +22,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiMethodUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -80,7 +80,7 @@ public class ConvertCompareToToEqualsIntention extends BaseElementAtCaretIntenti PsiMethodCallExpression compareToExpression = null; boolean hasZero = false; for (PsiExpression psiExpression : binaryExpression.getOperands()) { - if (compareToExpression == null && detectCompareTo(psiExpression)) { + if (compareToExpression == null && PsiMethodUtil.isCompareToCall(psiExpression)) { compareToExpression = (PsiMethodCallExpression)psiExpression; continue; } @@ -95,36 +95,6 @@ public class ConvertCompareToToEqualsIntention extends BaseElementAtCaretIntenti return new ResolveResult(binaryExpression, compareToExpression, isEqEq); } - private static boolean detectCompareTo(final @NotNull PsiExpression expression) { - if (!(expression instanceof PsiMethodCallExpression)) { - return false; - } - final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression; - if (methodCallExpression.getMethodExpression().getQualifierExpression() == null) { - return false; - } - final PsiMethod psiMethod = methodCallExpression.resolveMethod(); - if (psiMethod == null || !"compareTo".equals(psiMethod.getName()) || psiMethod.getParameterList().getParametersCount() != 1) { - return false; - } - if (methodCallExpression.getArgumentList().getExpressions().length != 1) { - return false; - } - final PsiClass containingClass = psiMethod.getContainingClass(); - if (containingClass == null) { - return false; - } - final PsiClass javaLangComparable = JavaPsiFacade.getInstance(expression.getProject()).findClass(CommonClassNames.JAVA_LANG_COMPARABLE, GlobalSearchScope.allScope( - expression.getProject())); - if (javaLangComparable == null) { - return false; - } - if (!containingClass.isInheritor(javaLangComparable, true)) { - return false; - } - return true; - } - private static boolean detectZero(final @NotNull PsiExpression expression) { if (!(expression instanceof PsiLiteralExpression)) { return false; diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiMethodUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiMethodUtil.java index 7a4d333b15f5..5082112471fa 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiMethodUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiMethodUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -19,6 +19,8 @@ import com.intellij.codeInsight.runner.JavaMainMethodProvider; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Condition; import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -89,4 +91,35 @@ public class PsiMethodUtil { } return findMainMethod(aClass); } + + public static boolean isCompareToCall(final @NotNull PsiExpression expression) { + if (!(expression instanceof PsiMethodCallExpression)) { + return false; + } + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression; + if (methodCallExpression.getMethodExpression().getQualifierExpression() == null) { + return false; + } + final PsiMethod psiMethod = methodCallExpression.resolveMethod(); + if (psiMethod == null || !"compareTo".equals(psiMethod.getName()) || psiMethod.getParameterList().getParametersCount() != 1) { + return false; + } + if (methodCallExpression.getArgumentList().getExpressions().length != 1) { + return false; + } + final PsiClass containingClass = psiMethod.getContainingClass(); + if (containingClass == null) { + return false; + } + final PsiClass javaLangComparable = JavaPsiFacade.getInstance(expression.getProject()).findClass(CommonClassNames.JAVA_LANG_COMPARABLE, GlobalSearchScope + .allScope( + expression.getProject())); + if (javaLangComparable == null) { + return false; + } + if (!containingClass.isInheritor(javaLangComparable, true)) { + return false; + } + return true; + } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators/afterSimple.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators/afterSimple.java new file mode 100644 index 000000000000..5b3790b30a90 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators/afterSimple.java @@ -0,0 +1,14 @@ +// "Replace with Comparator.comparing" "true" + +import java.util.Comparator; +import java.util.List; + +public class Main { + interface Person { + String getName(); + } + + void sort(List persons) { + persons.sort(Comparator.comparing(Person::getName)); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators/beforeInverted.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators/beforeInverted.java new file mode 100644 index 000000000000..e9e3679ee35d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators/beforeInverted.java @@ -0,0 +1,13 @@ +// "Replace with Comparator.comparing" "false" + +import java.util.List; + +public class Main { + interface Person { + String getName(); + } + + void sort(List persons) { + persons.sort((p1, p2) -> p2.getName().compareTo(p1.getName())); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators/beforeSimple.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators/beforeSimple.java new file mode 100644 index 000000000000..6a1e8856b116 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators/beforeSimple.java @@ -0,0 +1,13 @@ +// "Replace with Comparator.comparing" "true" + +import java.util.List; + +public class Main { + interface Person { + String getName(); + } + + void sort(List persons) { + persons.sort((p1, p2) -> p1.getName().compareTo(p2.getName())); + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ComparatorCombinatorsInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ComparatorCombinatorsInspectionTest.java new file mode 100644 index 000000000000..308d18534662 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ComparatorCombinatorsInspectionTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2016 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 com.intellij.codeInsight.daemon.quickFix; + +import com.intellij.codeInspection.ComparatorCombinatorsInspection; +import com.intellij.codeInspection.LocalInspectionTool; +import org.jetbrains.annotations.NotNull; + + +public class ComparatorCombinatorsInspectionTest extends LightQuickFixParameterizedTestCase { + @NotNull + @Override + protected LocalInspectionTool[] configureLocalInspectionTools() { + return new LocalInspectionTool[]{ + new ComparatorCombinatorsInspection() + }; + } + + public void test() throws Exception { doAllTests(); } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/comparatorCombinators"; + } +} \ No newline at end of file diff --git a/resources-en/src/inspectionDescriptions/ComparatorCombinators.html b/resources-en/src/inspectionDescriptions/ComparatorCombinators.html new file mode 100644 index 000000000000..d1812075c369 --- /dev/null +++ b/resources-en/src/inspectionDescriptions/ComparatorCombinators.html @@ -0,0 +1,10 @@ + + +Inspection looks for Comparators defined as lambda expressions which could be expressed using +methods like Comparator.comparing(). + +Some comparators like (person1, person2) -> person1.getName().compareTo(person2.getName()) +could be simplified like this: Comparator.comparing(Person::getName). +New in 2016.3 + + \ No newline at end of file diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index e2d6a8c17c3e..655a60c72fea 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -820,6 +820,10 @@ groupKey="group.names.declaration.redundancy" enabledByDefault="true" level="WARNING" implementationClass="com.intellij.codeInspection.SimplifyStreamApiCallChainsInspection" displayName="Simplify stream API call chains"/> + Date: Fri, 9 Sep 2016 15:54:02 +0300 Subject: [PATCH 05/24] minor UI changes to unused declaration (IDEA-160972) --- .../codeInspection/ex/ClassPatternsPanel.java | 23 ++++--------------- .../ex/EntryPointsManagerImpl.java | 4 ++-- .../UnusedAssignment.html | 3 +-- .../src/inspectionDescriptions/unused.html | 9 +++++--- 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/ClassPatternsPanel.java b/java/java-impl/src/com/intellij/codeInspection/ex/ClassPatternsPanel.java index 52665f885e76..1d6dae09c686 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/ClassPatternsPanel.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/ClassPatternsPanel.java @@ -24,14 +24,13 @@ import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.InputValidatorEx; -import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.ex.MultiLineLabel; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiNameHelper; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.*; import com.intellij.ui.table.JBTable; -import com.intellij.util.IconUtil; import com.intellij.util.ui.ItemRemovable; import com.intellij.util.ui.JBDimension; import com.intellij.util.ui.UIUtil; @@ -51,7 +50,6 @@ class ClassPatternsPanel extends JPanel { super(new BorderLayout()); myModifiedPatterns = patterns; myTable = createTableForPatterns(); - final String addPatternMessage = "Add Class Name Pattern"; final String addClassMessage = "Add Class"; final ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myTable) .setAddAction(new AnActionButtonRunnable() { @@ -69,18 +67,6 @@ class ClassPatternsPanel extends JPanel { } }) .setAddActionName(addClassMessage) - .setAddIcon(IconUtil.getAddClassIcon()) - .addExtraAction(new AnActionButton(addPatternMessage, IconUtil.getAddPatternIcon()) { - @Override - public void actionPerformed(AnActionEvent e) { - final PsiNameHelper nameHelper = PsiNameHelper.getInstance(e.getProject()); - String selectedPattern = Messages.showInputDialog("Pattern:", "Class Name Pattern", Messages.getQuestionIcon(), null, - new ClassPatternValidator(nameHelper)); - if (selectedPattern != null) { - insertRow(selectedPattern); - } - } - }) .setRemoveAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton button) { @@ -93,10 +79,11 @@ class ClassPatternsPanel extends JPanel { public boolean isEnabled(AnActionEvent e) { return myTable.getSelectedRow() >= 0; } - }) - .setButtonComparator(addClassMessage, addPatternMessage, "Remove"); + }); add(SeparatorFactory.createSeparator("Mark code as entry point if qualified name matches", null), BorderLayout.NORTH); add(toolbarDecorator.createPanel(), BorderLayout.CENTER); + add(new MultiLineLabel("Leave method blank to represent constructors\n" + + "Any * will match against one ore more characters in the qualified name (including dots)"), BorderLayout.SOUTH); setPreferredSize(new JBDimension(-1, 250)); } @@ -124,7 +111,7 @@ class ClassPatternsPanel extends JPanel { int row, int column) { final Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - if (!hasFocus && !isSelected && value instanceof String && ((String)value).isEmpty()) { + if (value instanceof String && ((String)value).isEmpty()) { setText("constructors"); setForeground(UIUtil.getInactiveTextColor()); } diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java index f5cda4cdcefd..cb2511d34389 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java @@ -55,7 +55,7 @@ public class EntryPointsManagerImpl extends EntryPointsManagerBase implements Pe final List writeList = new ArrayList<>(myWriteAnnotations); final JPanel listPanel = SpecialAnnotationsUtil.createSpecialAnnotationsListControl(list, "Mark as entry point if annotated by", true); - final JPanel writeAnnotationsPanel = SpecialAnnotationsUtil.createSpecialAnnotationsListControl(writeList, "Mark field as implicitly write if annotated by", false); + final JPanel writtenAnnotationsPanel = SpecialAnnotationsUtil.createSpecialAnnotationsListControl(writeList, "Mark field as implicitly written if annotated by", false); new DialogWrapper(myProject) { { init(); @@ -66,7 +66,7 @@ public class EntryPointsManagerImpl extends EntryPointsManagerBase implements Pe protected JComponent createCenterPanel() { final JPanel panel = new JPanel(new VerticalFlowLayout()); panel.add(listPanel); - panel.add(writeAnnotationsPanel); + panel.add(writtenAnnotationsPanel); return panel; } diff --git a/resources-en/src/inspectionDescriptions/UnusedAssignment.html b/resources-en/src/inspectionDescriptions/UnusedAssignment.html index a4474424f357..7279ce9921d2 100644 --- a/resources-en/src/inspectionDescriptions/UnusedAssignment.html +++ b/resources-en/src/inspectionDescriptions/UnusedAssignment.html @@ -4,7 +4,6 @@ This inspection points out the cases where a variable value is never used after its assignment, i.e.:
 - the variable never gets read after assignment OR
 - the value is always overwritten with another assignment before the next variable read OR
- - the variable initializer is redundant (for one of the above two reasons) OR
- - the variable is never used. + - the variable initializer is redundant (for one of the above two reasons) diff --git a/resources-en/src/inspectionDescriptions/unused.html b/resources-en/src/inspectionDescriptions/unused.html index 8687538f6d3f..9109539f38cc 100644 --- a/resources-en/src/inspectionDescriptions/unused.html +++ b/resources-en/src/inspectionDescriptions/unused.html @@ -2,10 +2,13 @@ This inspection reports classes, methods or fields in the specified inspection scope that are not used or not reachable from entry points. It also reports parameters that are not used by their methods and all method -implementations/overriders. -In editor, it also detects local variables that are declared but not used as well as private members that are never accessed for reading or not initialized in a class.

+implementations/overriders and local variables that are declared but not used.

+Use visibility settings below to configure what members should be reported, e.g. configuring report private methods only means +that public methods of private inner class would be reported though protected methods of top level class would be ignored. +
Use check boxes in the inspection options below, to specify what should be automatically assumed entry points. You will -also have a possibility to add entry points manually when inspection results are ready. +also have a possibility to add entry points manually when inspection results are ready. You may also configure annotations to mark members as entry points as well +as code patterns. From 77c387a506935837426245ba627a05163d7a2248 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 9 Sep 2016 16:35:10 +0300 Subject: [PATCH 06/24] layout unused declarations (IDEA-160479) --- .../deadCode/UnusedDeclarationInspection.java | 62 ++++++++++++++----- .../ex/EntryPointsManagerImpl.java | 4 +- .../src/inspectionDescriptions/unused.html | 2 +- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java index 658ba21f5290..98b0b6423a9d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationInspection.java @@ -34,6 +34,7 @@ import com.intellij.ui.components.JBLabel; import com.intellij.ui.components.JBRadioButton; import com.intellij.ui.components.JBTabbedPane; import com.intellij.util.ObjectUtils; +import com.intellij.util.ui.JBInsets; import com.intellij.util.ui.JBUI; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; @@ -144,11 +145,13 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase gc.fill = GridBagConstraints.HORIZONTAL; gc.anchor = GridBagConstraints.NORTHWEST; gc.gridx = 0; - gc.gridy = GridBagConstraints.RELATIVE; + gc.gridy = 0; + gc.gridwidth = 2; + add(new JBLabel("When entry points are in test sources, mark callees as:"), gc); + gc.gridy++; - add(new JBLabel("When entry point is located in test sources:"), gc); - final JBRadioButton asEntryPoint = new JBRadioButton("Treat as entry point", isTestEntryPoints()); - final JBRadioButton asUnused = new JBRadioButton("Mark callees as unused", !isTestEntryPoints()); + final JBRadioButton asEntryPoint = new JBRadioButton("used", isTestEntryPoints()); + final JBRadioButton asUnused = new JBRadioButton("unused", !isTestEntryPoints()); final ButtonGroup group = new ButtonGroup(); group.add(asEntryPoint); group.add(asUnused); @@ -160,11 +163,28 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase }; asEntryPoint.addActionListener(listener); asUnused.addActionListener(listener); - add(asEntryPoint, gc); - add(asUnused, gc); - add(new TitledSeparator(), gc); - gc.insets = JBUI.insets(0, 20, 2, 0); + gc.gridwidth = 1; + gc.weightx = 0; + add(asEntryPoint, gc); + gc.gridx = 1; + gc.weightx = 1; + add(asUnused, gc); + + gc.gridx = 0; + gc.gridy++; + + gc.gridwidth = 2; + add(new TitledSeparator(), gc); + gc.gridy++; + add(new JBLabel("Entry points:"), gc); + gc.insets = JBUI.insets(5, 0, 0, 0); + gc.gridy++; + + add(createBtnPanel(), gc); + gc.gridy++; + gc.insets = JBUI.insets(0, 5, 2, 0); + myMainsCheckbox = new JCheckBox(InspectionsBundle.message("inspection.dead.code.option.main")); myMainsCheckbox.setSelected(ADD_MAINS_TO_ENTRIES); myMainsCheckbox.addActionListener(new ActionListener() { @@ -176,6 +196,7 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase add(myMainsCheckbox, gc); + gc.gridy++; myAppletToEntries = new JCheckBox(InspectionsBundle.message("inspection.dead.code.option.applet")); myAppletToEntries.setSelected(ADD_APPLET_TO_ENTRIES); @@ -186,6 +207,7 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase } }); add(myAppletToEntries, gc); + gc.gridy++; myServletToEntries = new JCheckBox(InspectionsBundle.message("inspection.dead.code.option.servlet")); myServletToEntries.setSelected(ADD_SERVLET_TO_ENTRIES); @@ -196,6 +218,7 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase } }); add(myServletToEntries, gc); + gc.gridy++; for (final EntryPoint extension : myExtensions) { if (extension.showUI()) { @@ -208,6 +231,7 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase } }); add(extCheckbox, gc); + gc.gridy++; } } @@ -221,16 +245,24 @@ public class UnusedDeclarationInspection extends UnusedDeclarationInspectionBase } }); - add(myNonJavaCheckbox, gc); - - gc.fill = GridBagConstraints.NONE; gc.weighty = 1; - final JPanel btnPanel = new JPanel(new VerticalFlowLayout()); - btnPanel.add(EntryPointsManagerImpl.createConfigureClassPatternsButton()); - btnPanel.add(EntryPointsManagerImpl.createConfigureAnnotationsButton()); - add(btnPanel, gc); + add(myNonJavaCheckbox, gc); } + private JPanel createBtnPanel() { + final JPanel btnPanel = new JPanel(new GridBagLayout()); + GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = GridBagConstraints.NORTHWEST; + constraints.fill = GridBagConstraints.NONE; + constraints.weightx = 0; + btnPanel.add(EntryPointsManagerImpl.createConfigureClassPatternsButton(), constraints); + constraints.gridx = 1; + btnPanel.add(EntryPointsManagerImpl.createConfigureAnnotationsButton(), constraints); + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.weightx = 1; + btnPanel.add(Box.createHorizontalBox(), constraints); + return btnPanel; + } } private class UnusedVariablesGraphAnnotator extends RefGraphAnnotator { diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java index cb2511d34389..eb0142ac4541 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java @@ -90,7 +90,7 @@ public class EntryPointsManagerImpl extends EntryPointsManagerBase implements Pe } public static JButton createConfigureAnnotationsButton() { - final JButton configureAnnotations = new JButton("Configure annotations..."); + final JButton configureAnnotations = new JButton("Annotations..."); configureAnnotations.setHorizontalAlignment(SwingConstants.LEFT); configureAnnotations.addActionListener(new ActionListener() { @Override @@ -102,7 +102,7 @@ public class EntryPointsManagerImpl extends EntryPointsManagerBase implements Pe } public static JButton createConfigureClassPatternsButton() { - final JButton configureClassPatterns = new JButton("Configure code patterns..."); + final JButton configureClassPatterns = new JButton("Code patterns..."); configureClassPatterns.setHorizontalAlignment(SwingConstants.LEFT); configureClassPatterns.addActionListener(new ActionListener() { @Override diff --git a/resources-en/src/inspectionDescriptions/unused.html b/resources-en/src/inspectionDescriptions/unused.html index 9109539f38cc..3116e235d1b9 100644 --- a/resources-en/src/inspectionDescriptions/unused.html +++ b/resources-en/src/inspectionDescriptions/unused.html @@ -6,7 +6,7 @@ implementations/overriders and local variables that are declared but not used. Use visibility settings below to configure what members should be reported, e.g. configuring report private methods only means that public methods of private inner class would be reported though protected methods of top level class would be ignored. -
+

Use check boxes in the inspection options below, to specify what should be automatically assumed entry points. You will also have a possibility to add entry points manually when inspection results are ready. You may also configure annotations to mark members as entry points as well as code patterns. From 6e9f731d2def79afb05ce2f2f816617078fc105b Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 9 Sep 2016 16:51:06 +0300 Subject: [PATCH 07/24] unused declaration: filter annotations with field target type (IDEA-160974) --- .../codeInspection/ex/EntryPointsManagerImpl.java | 12 +++++++++++- .../codeInspection/util/SpecialAnnotationsUtil.java | 13 ++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java index eb0142ac4541..de4ea45e8a03 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/ex/EntryPointsManagerImpl.java @@ -24,6 +24,8 @@ */ package com.intellij.codeInspection.ex; +import com.intellij.codeInsight.AnnotationTargetUtil; +import com.intellij.codeInsight.AnnotationUtil; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInspection.util.SpecialAnnotationsUtil; import com.intellij.openapi.components.PersistentStateComponent; @@ -33,6 +35,9 @@ import com.intellij.openapi.project.ProjectUtil; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.VerticalFlowLayout; +import com.intellij.openapi.util.Condition; +import com.intellij.psi.PsiAnnotation; +import com.intellij.psi.PsiClass; import org.jdom.Element; import org.jetbrains.annotations.Nullable; @@ -42,6 +47,7 @@ import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; @State(name = "EntryPointsManager") public class EntryPointsManagerImpl extends EntryPointsManagerBase implements PersistentStateComponent { @@ -55,7 +61,11 @@ public class EntryPointsManagerImpl extends EntryPointsManagerBase implements Pe final List writeList = new ArrayList<>(myWriteAnnotations); final JPanel listPanel = SpecialAnnotationsUtil.createSpecialAnnotationsListControl(list, "Mark as entry point if annotated by", true); - final JPanel writtenAnnotationsPanel = SpecialAnnotationsUtil.createSpecialAnnotationsListControl(writeList, "Mark field as implicitly written if annotated by", false); + Condition applicableToField = psiClass -> { + Set annotationTargets = AnnotationTargetUtil.getAnnotationTargets(psiClass); + return annotationTargets != null && annotationTargets.contains(PsiAnnotation.TargetType.FIELD); + }; + final JPanel writtenAnnotationsPanel = SpecialAnnotationsUtil.createSpecialAnnotationsListControl(writeList, "Mark field as implicitly written if annotated by", false, applicableToField); new DialogWrapper(myProject) { { init(); diff --git a/java/java-impl/src/com/intellij/codeInspection/util/SpecialAnnotationsUtil.java b/java/java-impl/src/com/intellij/codeInspection/util/SpecialAnnotationsUtil.java index 8d5805ebaa02..ccc0845ec42f 100644 --- a/java/java-impl/src/com/intellij/codeInspection/util/SpecialAnnotationsUtil.java +++ b/java/java-impl/src/com/intellij/codeInspection/util/SpecialAnnotationsUtil.java @@ -24,24 +24,24 @@ import com.intellij.ide.util.TreeClassChooser; import com.intellij.ide.util.TreeClassChooserFactory; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Condition; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.*; import com.intellij.ui.components.JBList; import com.intellij.util.IconUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.Predicate; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import java.awt.*; -import java.util.Comparator; import java.util.List; /** @@ -55,6 +55,13 @@ public class SpecialAnnotationsUtil { public static JPanel createSpecialAnnotationsListControl(final List list, final String borderTitle, final boolean acceptPatterns) { + return createSpecialAnnotationsListControl(list, borderTitle, acceptPatterns, aClass -> aClass.isAnnotationType()); + } + + public static JPanel createSpecialAnnotationsListControl(final List list, + final String borderTitle, + final boolean acceptPatterns, + final Condition isApplicable) { final SortedListModel listModel = new SortedListModel<>((o1, o2) -> o1.compareTo(o2)); final JList injectionList = new JBList(listModel); for (String s : list) { @@ -96,7 +103,7 @@ public class SpecialAnnotationsUtil { GlobalSearchScope.allScope(project), new ClassFilter() { @Override public boolean isAccepted(PsiClass aClass) { - return aClass.isAnnotationType(); + return isApplicable.value(aClass); } }, null); chooser.showDialog(); From fe3c8e1843e93eb934690d7f3b5cd38fef25ee47 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 9 Sep 2016 17:23:23 +0300 Subject: [PATCH 08/24] create from usage: setup extends/implements list according to created pairs (IDEA-160973) --- .../impl/quickfix/CreateFromUsageUtils.java | 18 ++++++++++++------ .../quickfix/CreateInnerClassFromUsageFix.java | 6 +----- .../afterSuperInterface.java | 12 ++++++++++++ .../beforeSuperInterface.java | 9 +++++++++ 4 files changed, 34 insertions(+), 11 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/afterSuperInterface.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/beforeSuperInterface.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java index 7f89478a3439..265558f94709 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageUtils.java @@ -453,12 +453,7 @@ public class CreateFromUsageUtils { } if (superClassName != null && (classKind != CreateClassKind.ENUM || !superClassName.equals(CommonClassNames.JAVA_LANG_ENUM))) { - final PsiClass superClass = - facade.findClass(superClassName, targetClass.getResolveScope()); - final PsiJavaCodeReferenceElement superClassReference = factory.createReferenceElementByFQClassName(superClassName, targetClass.getResolveScope()); - final PsiReferenceList list = classKind == CreateClassKind.INTERFACE || superClass == null || !superClass.isInterface() ? - targetClass.getExtendsList() : targetClass.getImplementsList(); - list.add(superClassReference); + setupSuperClassReference(targetClass, superClassName); } if (contextElement instanceof PsiJavaCodeReferenceElement) { CreateFromUsageBaseFix.setupGenericParameters(targetClass, (PsiJavaCodeReferenceElement)contextElement); @@ -473,6 +468,17 @@ public class CreateFromUsageUtils { }); } + public static void setupSuperClassReference(PsiClass targetClass, String superClassName) { + JavaPsiFacade facade = JavaPsiFacade.getInstance(targetClass.getProject()); + PsiElementFactory factory = facade.getElementFactory(); + final PsiClass superClass = + facade.findClass(superClassName, targetClass.getResolveScope()); + final PsiJavaCodeReferenceElement superClassReference = factory.createReferenceElementByFQClassName(superClassName, targetClass.getResolveScope()); + final PsiReferenceList list = targetClass.isInterface() || superClass == null || !superClass.isInterface() ? + targetClass.getExtendsList() : targetClass.getImplementsList(); + list.add(superClassReference); + } + public static void scheduleFileOrPackageCreationFailedMessageBox(final IncorrectOperationException e, final String name, final PsiDirectory directory, final boolean isPackage) { ApplicationManager.getApplication().invokeLater(() -> Messages.showErrorDialog(QuickFixBundle.message( diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateInnerClassFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateInnerClassFromUsageFix.java index 25fc08e37dc6..5b4189b910af 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateInnerClassFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateInnerClassFromUsageFix.java @@ -150,11 +150,7 @@ public class CreateInnerClassFromUsageFix extends CreateClassFromUsageBaseFix { modifierList.setModifierProperty(PsiModifier.STATIC, true); } if (superClassName != null) { - PsiJavaCodeReferenceElement superClass = - elementFactory.createReferenceElementByFQClassName(superClassName, created.getResolveScope()); - final PsiReferenceList extendsList = created.getExtendsList(); - LOG.assertTrue(extendsList != null); - extendsList.add(superClass); + CreateFromUsageUtils.setupSuperClassReference(created, superClassName); } CreateFromUsageBaseFix.setupGenericParameters(created, ref); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/afterSuperInterface.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/afterSuperInterface.java new file mode 100644 index 000000000000..dd1e81c63cc2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/afterSuperInterface.java @@ -0,0 +1,12 @@ +// "Create inner class 'MyRunnable'" "true" +public class Test { + void bar(Class c) { + } + + void foo() { + bar(MyRunnable.class); + } + + private class MyRunnable implements Runnable { + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/beforeSuperInterface.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/beforeSuperInterface.java new file mode 100644 index 000000000000..d992b5920332 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/beforeSuperInterface.java @@ -0,0 +1,9 @@ +// "Create inner class 'MyRunnable'" "true" +public class Test { + void bar(Class c) { + } + + void foo() { + bar(MyRunnable.class); + } +} \ No newline at end of file From 58ad02077e3f035431d129330be40c2cee3ad06f Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 9 Sep 2016 17:37:21 +0300 Subject: [PATCH 09/24] testng: filter suite elements from pattern based (IDEA-160944) --- .../AbstractPatternBasedConfigurationProducer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/testframework/AbstractPatternBasedConfigurationProducer.java b/java/execution/impl/src/com/intellij/execution/testframework/AbstractPatternBasedConfigurationProducer.java index 2a91cf8c4343..bee7e6c58387 100644 --- a/java/execution/impl/src/com/intellij/execution/testframework/AbstractPatternBasedConfigurationProducer.java +++ b/java/execution/impl/src/com/intellij/execution/testframework/AbstractPatternBasedConfigurationProducer.java @@ -228,8 +228,10 @@ public abstract class AbstractPatternBasedConfigurationProducer elements = new ArrayList<>(); for (Location location : locations) { final PsiElement psiElement = location.getPsiElement(); - classes.add(getQName(psiElement, location)); - elements.add(psiElement); + if (psiElement instanceof PsiNamedElement) { + classes.add(getQName(psiElement, location)); + elements.add(psiElement); + } } return elements.toArray(new PsiElement[elements.size()]); } From f5262aa97c5a113b1547f3ed0bf7c6f15ce43da0 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 9 Sep 2016 20:12:22 +0300 Subject: [PATCH 10/24] test runner: append output after last passed child (IDEA-160397) --- .../testframework/sm/runner/SMTestProxy.java | 8 +-- .../testframework/sm/runner/OutputTest.kt | 69 +++++++++++++++++++ .../testframework/AbstractTestProxy.java | 15 +++- 3 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/OutputTest.kt diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java index bb566a29b1d6..ec85b930c96a 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/SMTestProxy.java @@ -581,7 +581,7 @@ public class SMTestProxy extends AbstractTestProxy { } public void addStdOutput(final String output, final Key outputType) { - addLast(new Printable() { + addAfterLastPassed(new Printable() { public void printOn(final Printer printer) { printer.print(output, ConsoleViewContentType.getConsoleViewType(outputType)); } @@ -589,7 +589,7 @@ public class SMTestProxy extends AbstractTestProxy { } public void addStdErr(final String output) { - addLast(new Printable() { + addAfterLastPassed(new Printable() { public void printOn(final Printer printer) { printer.print(output, ConsoleViewContentType.ERROR_OUTPUT); } @@ -615,7 +615,7 @@ public class SMTestProxy extends AbstractTestProxy { } setStacktraceIfNotSet(stackTrace); - addLast(new Printable() { + addAfterLastPassed(new Printable() { public void printOn(final Printer printer) { String errorText = TestFailedState.buildErrorPresentationText(output, stackTrace); LOG.assertTrue(errorText != null); @@ -634,7 +634,7 @@ public class SMTestProxy extends AbstractTestProxy { } public void addSystemOutput(final String output) { - addLast(new Printable() { + addAfterLastPassed(new Printable() { public void printOn(final Printer printer) { printer.print(output, ConsoleViewContentType.SYSTEM_OUTPUT); } diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/OutputTest.kt b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/OutputTest.kt new file mode 100644 index 000000000000..dc66631ff6d9 --- /dev/null +++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/OutputTest.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2016 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 com.intellij.execution.testframework.sm.runner + +import com.intellij.execution.process.ProcessOutputTypes +import com.intellij.execution.testframework.sm.runner.ui.MockPrinter +import com.intellij.openapi.util.Disposer + +class OutputTest : BaseSMTRunnerTestCase() { + fun testBeforeAfterOrder() { + val suite = createTestProxy("parent") + val child = createTestProxy("child", suite) + + suite.addStdOutput("before test started\n", ProcessOutputTypes.STDOUT) + child.setStarted() + child.addStdOutput("inside test\n", ProcessOutputTypes.STDOUT) + child.setFinished() + suite.addStdOutput("after test finished\n", ProcessOutputTypes.STDOUT) + + val printer = MockPrinter(true) + suite.printOn(printer) + + assertEquals("before test started\ninside test\nafter test finished\n", printer.stdOut) + printer.resetIfNecessary() + + child.printOn(printer) + assertEquals("inside test\n", printer.stdOut) + } + + fun testBeforeAfterOrderWhenFlushed() { + val suite = createTestProxy("parent") + val child = createTestProxy("child", suite) + + try { + suite.addStdOutput("before test started\n", ProcessOutputTypes.STDOUT) + child.setStarted() + child.addStdOutput("inside test\n", ProcessOutputTypes.STDOUT) + child.setFinished() + suite.flush() + suite.addStdOutput("after test finished\n", ProcessOutputTypes.STDOUT) + + val printer = MockPrinter(true) + suite.printOn(printer) + + assertEquals("before test started\ninside test\nafter test finished\n", printer.stdOut) + printer.resetIfNecessary() + + child.printOn(printer) + assertEquals("inside test\n", printer.stdOut) + } + finally { + Disposer.dispose(child) + Disposer.dispose(suite) + } + } +} \ No newline at end of file diff --git a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java index c60de5c69027..10a283bd3292 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java @@ -148,7 +148,20 @@ public abstract class AbstractTestProxy extends CompositePrintable { final DiffHyperlink provider = getDiffViewerProvider(); return provider == null ? Collections.emptyList() : Collections.singletonList(provider); } - + + protected void addAfterLastPassed(Printable printable) { + int idx = 0; + synchronized (myNestedPrintables) { + for (Printable proxy : myNestedPrintables) { + if (proxy instanceof AbstractTestProxy && !((AbstractTestProxy)proxy).isPassed()) { + break; + } + idx++; + } + } + insert(printable, idx); + } + @Nullable public DiffHyperlink getDiffViewerProvider() { return null; From 710891ee880cd9dabac66d51b2d76325cd48cb8f Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 12 Sep 2016 13:22:23 +0300 Subject: [PATCH 11/24] junit: ensure control operations are started from the new line (IDEA-158135) --- .../JUnitTreeByDescriptionHierarchyTest.java | 91 ++++++++++++++++--- .../intellij/junit4/JUnit4TestListener.java | 8 +- 2 files changed, 80 insertions(+), 19 deletions(-) diff --git a/plugins/junit/test/com/intellij/execution/junit/JUnitTreeByDescriptionHierarchyTest.java b/plugins/junit/test/com/intellij/execution/junit/JUnitTreeByDescriptionHierarchyTest.java index 25e535bba1ba..02278e0692b2 100644 --- a/plugins/junit/test/com/intellij/execution/junit/JUnitTreeByDescriptionHierarchyTest.java +++ b/plugins/junit/test/com/intellij/execution/junit/JUnitTreeByDescriptionHierarchyTest.java @@ -68,34 +68,45 @@ public class JUnitTreeByDescriptionHierarchyTest { "##teamcity[rootName name = 'root' location = 'java:suite://root']\n" + + "\n" + "##teamcity[testSuiteStarted name='TestA']\n" + + "\n" + "##teamcity[testSuiteStarted name='|[0|]']\n" + "\n" + "##teamcity[testStarted name='testName|[0|]' locationHint='java:test://a.TestA.testName|[0|]']\n" + "\n" + "##teamcity[testFinished name='testName|[0|]']\n" + + "\n" + "##teamcity[testSuiteFinished name='|[0|]']\n" + + "\n" + "##teamcity[testSuiteStarted name='|[1|]']\n" + "\n" + "##teamcity[testStarted name='testName|[1|]' locationHint='java:test://a.TestA.testName|[1|]']\n" + "\n" + "##teamcity[testFinished name='testName|[1|]']\n" + + "\n" + "##teamcity[testSuiteFinished name='|[1|]']\n" + + "\n" + "##teamcity[testSuiteFinished name='TestA']\n" + + "\n" + "##teamcity[testSuiteStarted name='TestB']\n" + + "\n" + "##teamcity[testSuiteStarted name='|[0|]']\n" + "\n" + "##teamcity[testStarted name='testName|[0|]' locationHint='java:test://a.TestB.testName|[0|]']\n" + "\n" + "##teamcity[testFinished name='testName|[0|]']\n" + + "\n" + "##teamcity[testSuiteFinished name='|[0|]']\n" + + "\n" + "##teamcity[testSuiteStarted name='|[1|]']\n" + "\n" + "##teamcity[testStarted name='testName|[1|]' locationHint='java:test://a.TestB.testName|[1|]']\n" + "\n" + "##teamcity[testFinished name='testName|[1|]']\n" + + "\n" + "##teamcity[testSuiteFinished name='|[1|]']\n" + - "##teamcity[testSuiteFinished name='TestB']\n"); + "##teamcity[testSuiteFinished name='TestB']"); } @Test @@ -119,6 +130,7 @@ public class JUnitTreeByDescriptionHierarchyTest { } sender.testRunFinished(new Result()); Assert.assertEquals("output: " + buf, "##teamcity[enteredTheMatrix]\n" + + "\n" + "##teamcity[testSuiteStarted name='ATest' locationHint='java:suite://ATest']\n" + "\n" + "##teamcity[testStarted name='ATest.test1' locationHint='java:test://ATest.test1']\n" + @@ -128,7 +140,8 @@ public class JUnitTreeByDescriptionHierarchyTest { "##teamcity[testStarted name='ATest.test2' locationHint='java:test://ATest.test2']\n" + "\n" + "##teamcity[testFinished name='ATest.test2']\n" + - "##teamcity[testSuiteFinished name='ATest']\n", StringUtil.convertLineSeparators(buf.toString())); + "\n" + + "##teamcity[testSuiteFinished name='ATest']", StringUtil.convertLineSeparators(buf.toString())); } @Test @@ -151,19 +164,22 @@ public class JUnitTreeByDescriptionHierarchyTest { "##teamcity[suiteTreeEnded name='MyTest']\n" + "##teamcity[treeEnded]\n", "##teamcity[rootName name = 'root' location = 'java:suite://root']\n" + + "\n" + "##teamcity[testSuiteStarted name='MyTest']\n" + "\n" + "##teamcity[testStarted name='MyTest.testMe' locationHint='java:test://a.MyTest.testMe']\n" + "\n" + "##teamcity[testFinished name='MyTest.testMe']\n" + + "\n" + "##teamcity[testSuiteFinished name='MyTest']\n" + + "\n" + "##teamcity[testSuiteStarted name='MyTest']\n" + "\n" + "##teamcity[testStarted name='MyTest.testMe' locationHint='java:test://b.MyTest.testMe']\n" + "\n" + "##teamcity[testFinished name='MyTest.testMe']\n" + - "##teamcity[testSuiteFinished nam" + - "e='MyTest']\n"); + "\n" + + "##teamcity[testSuiteFinished name='MyTest']"); } @Test @@ -184,18 +200,22 @@ public class JUnitTreeByDescriptionHierarchyTest { "##teamcity[treeEnded]\n", //start "##teamcity[rootName name = 'TestA' comment = 'a' location = 'java:suite://a.TestA']\n" + + "\n" + "##teamcity[testSuiteStarted name='|[0|]']\n" + "\n" + "##teamcity[testStarted name='testName|[0|]' locationHint='java:test://a.TestA.testName|[0|]']\n" + "\n" + "##teamcity[testFinished name='testName|[0|]']\n" + + "\n" + "##teamcity[testSuiteFinished name='|[0|]']\n" + + "\n" + "##teamcity[testSuiteStarted name='|[1|]']\n" + "\n" + "##teamcity[testStarted name='testName|[1|]' locationHint='java:test://a.TestA.testName|[1|]']\n" + "\n" + "##teamcity[testFinished name='testName|[1|]']\n" + - "##teamcity[testSuiteFinished name='|[1|]']\n"); + "\n" + + "##teamcity[testSuiteFinished name='|[1|]']"); } @Test @@ -222,18 +242,22 @@ public class JUnitTreeByDescriptionHierarchyTest { "##teamcity[treeEnded]\n", //start "##teamcity[rootName name = 'TestA' comment = 'a' location = 'java:suite://a.TestA']\n" + + "\n" + "##teamcity[testSuiteStarted name='|[0|]']\n" + "\n" + "##teamcity[testStarted name='testName|[0|]' locationHint='java:test://a.TestA.testName|[0|]']\n" + "\n" + "##teamcity[testFinished name='testName|[0|]']\n" + + "\n" + "##teamcity[testSuiteFinished name='|[0|]']\n" + + "\n" + "##teamcity[testSuiteStarted name='|[0|]']\n" + "\n" + "##teamcity[testStarted name='testName|[0|]' locationHint='java:test://a.TestA.testName|[0|]']\n" + "\n" + "##teamcity[testFinished name='testName|[0|]']\n" + - "##teamcity[testSuiteFinished name='|[0|]']\n"); + "\n" + + "##teamcity[testSuiteFinished name='|[0|]']"); } @Test @@ -260,18 +284,22 @@ public class JUnitTreeByDescriptionHierarchyTest { "##teamcity[treeEnded]\n", //start "##teamcity[rootName name = 'TestA' comment = 'a' location = 'java:suite://a.TestA']\n" + + "\n" + "##teamcity[testSuiteStarted name='|[0: with - 1.1|]']\n" + "\n" + "##teamcity[testStarted name='testName|[0: with - 1.1|]' locationHint='java:test://a.TestA.testName|[0: with - 1.1|]']\n" + "\n" + "##teamcity[testFinished name='testName|[0: with - 1.1|]']\n" + + "\n" + "##teamcity[testSuiteFinished name='|[0: with - 1.1|]']\n" + + "\n" + "##teamcity[testSuiteStarted name='|[1: with - 2.1|]']\n" + "\n" + "##teamcity[testStarted name='testName|[1: with - 2.1|]' locationHint='java:test://a.TestA.testName|[1: with - 2.1|]']\n" + "\n" + "##teamcity[testFinished name='testName|[1: with - 2.1|]']\n" + - "##teamcity[testSuiteFinished name='|[1: with - 2.1|]']\n"); + "\n" + + "##teamcity[testSuiteFinished name='|[1: with - 2.1|]']"); } @Test @@ -307,22 +335,29 @@ public class JUnitTreeByDescriptionHierarchyTest { //started "##teamcity[rootName name = 'root' location = 'java:suite://root']\n" + + "\n" + "##teamcity[testSuiteStarted name='ASuite1']\n" + + "\n" + "##teamcity[testSuiteStarted name='ATest']\n" + "\n" + "##teamcity[testStarted name='ATest.test1' locationHint='java:test://ATest.test1']\n" + "\n" + "##teamcity[testFinished name='ATest.test1']\n" + + "\n" + "##teamcity[testSuiteFinished name='ATest']\n" + + "\n" + "##teamcity[testSuiteFinished name='ASuite1']\n" + + "\n" + "##teamcity[testSuiteStarted name='ASuite2']\n" + + "\n" + "##teamcity[testSuiteStarted name='ATest']\n" + "\n" + "##teamcity[testStarted name='ATest.test1' locationHint='java:test://ATest.test1']\n" + "\n" + "##teamcity[testFinished name='ATest.test1']\n" + + "\n" + "##teamcity[testSuiteFinished name='ATest']\n" + - "##teamcity[testSuiteFinished name='ASuite2']\n"); + "##teamcity[testSuiteFinished name='ASuite2']"); } private static void doTest(Description root, List tests, String expectedTree, String expectedStart) throws Exception { @@ -371,6 +406,7 @@ public class JUnitTreeByDescriptionHierarchyTest { sender.testRunFinished(new Result()); Assert.assertEquals("output: " + buf, "##teamcity[rootName name = 'root' location = 'java:suite://root']\n" + + "\n" + "##teamcity[testSuiteStarted name='TestA']\n" + "\n" + "##teamcity[testStarted name='TestA.testName' locationHint='java:test://TestA.testName']\n" + @@ -378,7 +414,8 @@ public class JUnitTreeByDescriptionHierarchyTest { "##teamcity[testIgnored name='TestA.testName' details='java.lang.Exception|n' error='true' message='']\n" + "\n" + "##teamcity[testFinished name='TestA.testName']\n" + - "##teamcity[testSuiteFinished name='TestA']\n", StringUtil.convertLineSeparators(buf.toString())); + "\n" + + "##teamcity[testSuiteFinished name='TestA']", StringUtil.convertLineSeparators(buf.toString())); } @Test @@ -408,11 +445,13 @@ public class JUnitTreeByDescriptionHierarchyTest { sender.testRunFinished(new Result()); Assert.assertEquals("output: " + buf, "##teamcity[rootName name = 'root' location = 'java:suite://root']\n" + + "\n" + "##teamcity[testStarted name='Class Configuration' locationHint='java:suite://TestA' ]\n" + "\n" + "##teamcity[testFailed name='Class Configuration' details='java.lang.Exception|n' error='true' message='']\n" + "\n" + "##teamcity[testFinished name='Class Configuration']\n" + + "\n" + "##teamcity[testSuiteStarted name='TestA']\n" + "\n" + "##teamcity[testStarted name='TestA.testName' locationHint='java:test://TestA.testName']\n" + @@ -420,7 +459,8 @@ public class JUnitTreeByDescriptionHierarchyTest { "##teamcity[testIgnored name='TestA.testName']\n" + "\n" + "##teamcity[testFinished name='TestA.testName']\n" + - "##teamcity[testSuiteFinished name='TestA']\n", StringUtil.convertLineSeparators(buf.toString())); + "\n" + + "##teamcity[testSuiteFinished name='TestA']", StringUtil.convertLineSeparators(buf.toString())); } @Test @@ -497,17 +537,20 @@ public class JUnitTreeByDescriptionHierarchyTest { sender.testRunFinished(new Result()); Assert.assertEquals("output: " + buf, "##teamcity[rootName name = 'root' location = 'java:suite://root']\n" + + "\n" + "##teamcity[testSuiteStarted name='TestA']\n" + "\n" + "##teamcity[testStarted name='TestA.testName' locationHint='java:test://TestA.testName']\n" + "\n" + "##teamcity[testFinished name='TestA.testName']\n" + + "\n" + "##teamcity[testStarted name='Class Configuration' locationHint='java:suite://TestA' ]\n" + "\n" + "##teamcity[testFailed name='Class Configuration' details='java.lang.Exception|n' error='true' message='']\n" + "\n" + "##teamcity[testFinished name='Class Configuration']\n" + - "##teamcity[testSuiteFinished name='TestA']\n", StringUtil.convertLineSeparators(buf.toString())); + "\n" + + "##teamcity[testSuiteFinished name='TestA']", StringUtil.convertLineSeparators(buf.toString())); } @Test @@ -541,7 +584,9 @@ public class JUnitTreeByDescriptionHierarchyTest { sender.testRunFinished(new Result()); Assert.assertEquals("output: " + buf, "##teamcity[rootName name = 'root' location = 'java:suite://root']\n" + + "\n" + "##teamcity[testSuiteStarted name='TestA']\n" + + "\n" + "##teamcity[testSuiteStarted name='param']\n" + "\n" + "##teamcity[testStarted name='TestA.testName' locationHint='java:test://TestA.testName']\n" + @@ -549,8 +594,9 @@ public class JUnitTreeByDescriptionHierarchyTest { "##teamcity[testIgnored name='TestA.testName' details='java.lang.Exception|n' error='true' message='']\n" + "\n" + "##teamcity[testFinished name='TestA.testName']\n" + + "\n" + "##teamcity[testSuiteFinished name='param']\n" + - "##teamcity[testSuiteFinished name='TestA']\n", StringUtil.convertLineSeparators(buf.toString())); + "##teamcity[testSuiteFinished name='TestA']", StringUtil.convertLineSeparators(buf.toString())); buf.setLength(0); //testStarted and testFinished are called by the framework @@ -601,18 +647,22 @@ public class JUnitTreeByDescriptionHierarchyTest { sender.testRunFinished(new Result()); Assert.assertEquals("output: " + buf, "##teamcity[enteredTheMatrix]\n" + + "\n" + "##teamcity[testSuiteStarted name='TestA' locationHint='java:suite://a.TestA']\n" + "\n" + "##teamcity[testStarted name='TestA.testName' locationHint='java:test://a.TestA.testName']\n" + "\n" + "##teamcity[testFinished name='TestA.testName']\n" + + "\n" + "##teamcity[testSuiteFinished name='TestA']\n" + + "\n" + "##teamcity[testSuiteStarted name='TestB' locationHint='java:suite://a.TestB']\n" + "\n" + "##teamcity[testStarted name='TestB.testName' locationHint='java:test://a.TestB.testName']\n" + "\n" + "##teamcity[testFinished name='TestB.testName']\n" + - "##teamcity[testSuiteFinished name='TestB']\n", StringUtil.convertLineSeparators(buf.toString())); + "\n" + + "##teamcity[testSuiteFinished name='TestB']", StringUtil.convertLineSeparators(buf.toString())); } private static JUnit4TestListener createListener(final StringBuffer buf) { @@ -655,6 +705,7 @@ public class JUnitTreeByDescriptionHierarchyTest { "##teamcity[rootName name = 'ATest' location = 'java:suite://ATest']\n" + + "\n" + "##teamcity[testSuiteStarted name='testName']\n" + "\n" + "##teamcity[testStarted name='ATest.testName|[0|]' locationHint='java:test://ATest.testName|[0|]']\n" + @@ -664,7 +715,8 @@ public class JUnitTreeByDescriptionHierarchyTest { "##teamcity[testStarted name='ATest.testName|[1|]' locationHint='java:test://ATest.testName|[1|]']\n" + "\n" + "##teamcity[testFinished name='ATest.testName|[1|]']\n" + - "##teamcity[testSuiteFinished name='testName']\n"); + "\n" + + "##teamcity[testSuiteFinished name='testName']"); } @Test @@ -700,28 +752,37 @@ public class JUnitTreeByDescriptionHierarchyTest { //start "##teamcity[rootName name = 'root' location = 'java:suite://root']\n" + + "\n" + "##teamcity[testSuiteStarted name='ATest']\n" + + "\n" + "##teamcity[testSuiteStarted name='|[0|]']\n" + "\n" + "##teamcity[testStarted name='testName|[0|]' locationHint='java:test://ATest.testName|[0|]']\n" + "\n" + "##teamcity[testFinished name='testName|[0|]']\n" + + "\n" + "##teamcity[testSuiteFinished name='|[0|]']\n" + + "\n" + "##teamcity[testSuiteStarted name='|[1|]']\n" + "\n" + "##teamcity[testStarted name='testName|[1|]' locationHint='java:test://ATest.testName|[1|]']\n" + "\n" + "##teamcity[testFinished name='testName|[1|]']\n" + + "\n" + "##teamcity[testSuiteFinished name='|[1|]']\n" + + "\n" + "##teamcity[testSuiteFinished name='ATest']\n" + + "\n" + "##teamcity[testSuiteStarted name='suite']\n" + + "\n" + "##teamcity[testSuiteStarted name='ATest']\n" + "\n" + "##teamcity[testStarted name='ATest.test' locationHint='java:test://ATest.test']\n" + "\n" + "##teamcity[testFinished name='ATest.test']\n" + + "\n" + "##teamcity[testSuiteFinished name='ATest']\n" + - "##teamcity[testSuiteFinished name='suite']\n"); + "##teamcity[testSuiteFinished name='suite']"); } diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestListener.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestListener.java index aa5ff995547d..b0885a7761cb 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestListener.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestListener.java @@ -86,7 +86,7 @@ public class JUnit4TestListener extends RunListener { dumpQueue(true); for (int i = myStartedSuites.size() - 1; i>= 0; i--) { Object parent = JUnit4ReflectionUtil.getClassName((Description)myStartedSuites.get(i)); - myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(getShortName((String)parent)) + "\']"); + myPrintStream.print("\n##teamcity[testSuiteFinished name=\'" + escapeName(getShortName((String)parent)) + "\']"); } myStartedSuites.clear(); } @@ -131,7 +131,7 @@ public class JUnit4TestListener extends RunListener { for (int i = myStartedSuites.size() - 1; i >= idx; i--) { currentClass = (Description)myStartedSuites.remove(i); myFinishedCount = 0; - myPrintStream.println("##teamcity[testSuiteFinished name=\'" + escapeName(getShortName(JUnit4ReflectionUtil.getClassName(currentClass))) + "\']"); + myPrintStream.println("\n##teamcity[testSuiteFinished name=\'" + escapeName(getShortName(JUnit4ReflectionUtil.getClassName(currentClass))) + "\']"); } for (int i = idx; i < parentsHierarchy.size(); i++) { @@ -139,7 +139,7 @@ public class JUnit4TestListener extends RunListener { final String fqName = JUnit4ReflectionUtil.getClassName(descriptionFromHistory); final String className = getShortName(fqName); if (!className.equals(myRootName)) { - myPrintStream.println("##teamcity[testSuiteStarted name=\'" + escapeName(className) + "\'" + (parents == null ? getClassLocation(fqName) : "") + "]"); + myPrintStream.println("\n##teamcity[testSuiteStarted name=\'" + escapeName(className) + "\'" + (parents == null ? getClassLocation(fqName) : "") + "]"); myStartedSuites.add(descriptionFromHistory); } } @@ -252,7 +252,7 @@ public class JUnit4TestListener extends RunListener { } myCurrentTest = description; - myPrintStream.println("##teamcity[testStarted name=\'" + escapeName(CLASS_CONFIGURATION) + "\' " + getClassLocation(JUnit4ReflectionUtil.getClassName(description)) + " ]"); + myPrintStream.println("\n##teamcity[testStarted name=\'" + escapeName(CLASS_CONFIGURATION) + "\' " + getClassLocation(JUnit4ReflectionUtil.getClassName(description)) + " ]"); } private void testFailure(Failure failure, Description description, String messageName, String methodName) { From 74afb35a8bbae90c1e9d936fefe97cf778f7132c Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Mon, 12 Sep 2016 14:54:55 +0300 Subject: [PATCH 12/24] add logging to investigate EA-88298 - assert: RootModelImpl.addLibraryEntry --- .../com/intellij/openapi/roots/impl/RootModelImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelImpl.java index 9e621cde6b22..d35d7ba66f8a 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelImpl.java @@ -33,6 +33,7 @@ import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager; import com.intellij.util.ArrayUtil; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -225,7 +226,14 @@ public class RootModelImpl extends RootModelBase implements ModifiableRootModel public LibraryOrderEntry addLibraryEntry(@NotNull Library library) { assertWritable(); final LibraryOrderEntry libraryOrderEntry = new LibraryOrderEntryImpl(library, this, myProjectRootManager); - assert libraryOrderEntry.isValid(); + if (libraryOrderEntry.isValid()) { + LibraryEx libraryEx = ObjectUtils.tryCast(library, LibraryEx.class); + boolean libraryDisposed = libraryEx != null ? libraryEx.isDisposed() : Disposer.isDisposed(library); + throw new AssertionError("Invalid libraryOrderEntry, library: " + library + + " of type " + library.getClass() + + ", disposed: " + libraryDisposed + + ", kind: " + (libraryEx != null ? libraryEx.getKind() : "")); + } myOrderEntries.add(libraryOrderEntry); return libraryOrderEntry; } From 3e5179b17aef321b16de9c1e671a819e9d93a728 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 12 Sep 2016 14:38:08 +0300 Subject: [PATCH 13/24] github: extract class --- .../plugins/github/api/GithubConnection.java | 124 +------------- .../github/api/GithubConnectionBuilder.java | 156 ++++++++++++++++++ 2 files changed, 157 insertions(+), 123 deletions(-) create mode 100644 plugins/github/src/org/jetbrains/plugins/github/api/GithubConnectionBuilder.java diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java index 249dc5beafc3..aa14956c789d 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java @@ -21,36 +21,17 @@ import com.google.gson.JsonParser; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.vfs.CharsetToolkit; -import com.intellij.util.net.IdeHttpClientHelpers; -import com.intellij.util.net.ssl.CertificateManager; import org.apache.http.*; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.Credentials; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.config.AuthSchemes; -import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.*; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.config.ConnectionConfig; -import org.apache.http.conn.ssl.X509HostnameVerifier; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; -import org.apache.http.impl.auth.BasicScheme; -import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.message.BasicHeader; -import org.apache.http.protocol.HttpContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import org.jetbrains.plugins.github.api.data.GithubErrorMessage; import org.jetbrains.plugins.github.exceptions.*; import org.jetbrains.plugins.github.util.GithubAuthData; -import org.jetbrains.plugins.github.util.GithubSettings; import org.jetbrains.plugins.github.util.GithubUrlUtil; import org.jetbrains.plugins.github.util.GithubUtil; @@ -60,7 +41,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; -import java.net.URISyntaxException; import java.security.cert.CertificateException; import java.util.*; import java.util.List; @@ -84,7 +64,7 @@ public class GithubConnection { public GithubConnection(@NotNull GithubAuthData auth, boolean reusable) { myHost = auth.getHost(); - myClient = createClient(auth); + myClient = new GithubConnectionBuilder(auth).createClient(); myReusable = reusable; } @@ -141,91 +121,6 @@ public class GithubConnection { myClient.close(); } - @NotNull - private static CloseableHttpClient createClient(@NotNull GithubAuthData auth) { - HttpClientBuilder builder = HttpClients.custom(); - - builder - .setDefaultRequestConfig(createRequestConfig(auth)) - .setDefaultConnectionConfig(createConnectionConfig(auth)) - .setDefaultHeaders(createHeaders(auth)) - .setSslcontext(CertificateManager.getInstance().getSslContext()) - .setHostnameVerifier((X509HostnameVerifier)CertificateManager.HOSTNAME_VERIFIER); - - setupCredentialsProvider(builder, auth); - - return builder.build(); - } - - @NotNull - private static RequestConfig createRequestConfig(@NotNull GithubAuthData auth) { - RequestConfig.Builder builder = RequestConfig.custom(); - - int timeout = GithubSettings.getInstance().getConnectionTimeout(); - builder - .setConnectTimeout(timeout) - .setSocketTimeout(timeout); - - if (auth.isUseProxy()) { - IdeHttpClientHelpers.ApacheHttpClient4.setProxyForUrlIfEnabled(builder, auth.getHost()); - } - - return builder.build(); - } - - @NotNull - private static ConnectionConfig createConnectionConfig(@NotNull GithubAuthData auth) { - return ConnectionConfig.custom() - .setCharset(Consts.UTF_8) - .build(); - } - - - @NotNull - private static CredentialsProvider setupCredentialsProvider(@NotNull HttpClientBuilder builder, @NotNull GithubAuthData auth) { - CredentialsProvider provider = new BasicCredentialsProvider(); - // Basic authentication - GithubAuthData.BasicAuth basicAuth = auth.getBasicAuth(); - if (basicAuth != null) { - AuthScope authScope = getBasicAuthScope(auth); - - provider.setCredentials(authScope, new UsernamePasswordCredentials(basicAuth.getLogin(), basicAuth.getPassword())); - builder.addInterceptorFirst(new PreemptiveBasicAuthInterceptor(authScope)); - } - builder.setDefaultCredentialsProvider(provider); - - if (auth.isUseProxy()) { - IdeHttpClientHelpers.ApacheHttpClient4.setProxyCredentialsForUrlIfEnabled(provider, auth.getHost()); - } - - return provider; - } - - @NotNull - private static AuthScope getBasicAuthScope(@NotNull GithubAuthData auth) { - try { - URIBuilder builder = new URIBuilder(auth.getHost()); - return new AuthScope(builder.getHost(), builder.getPort(), AuthScope.ANY_REALM, AuthSchemes.BASIC); - } - catch (URISyntaxException e) { - return AuthScope.ANY; - } - } - - @NotNull - private static Collection createHeaders(@NotNull GithubAuthData auth) { - List
headers = new ArrayList<>(); - GithubAuthData.TokenAuth tokenAuth = auth.getTokenAuth(); - if (tokenAuth != null) { - headers.add(new BasicHeader("Authorization", "token " + tokenAuth.getToken())); - } - GithubAuthData.BasicAuth basicAuth = auth.getBasicAuth(); - if (basicAuth != null && basicAuth.getCode() != null) { - headers.add(new BasicHeader("X-GitHub-OTP", basicAuth.getCode())); - } - return headers; - } - @NotNull private static String getRequestUrl(@NotNull String host, @NotNull String path) { return GithubUrlUtil.getApiUrl(host) + path; @@ -540,23 +435,6 @@ public class GithubConnection { } } - private static class PreemptiveBasicAuthInterceptor implements HttpRequestInterceptor { - @NotNull private final AuthScope myBasicAuthScope; - - public PreemptiveBasicAuthInterceptor(@NotNull AuthScope basicAuthScope) { - myBasicAuthScope = basicAuthScope; - } - - @Override - public void process(HttpRequest request, HttpContext context) throws HttpException, IOException { - CredentialsProvider provider = (CredentialsProvider)context.getAttribute(HttpClientContext.CREDS_PROVIDER); - Credentials credentials = provider.getCredentials(myBasicAuthScope); - if (credentials != null) { - request.addHeader(new BasicScheme(Consts.UTF_8).authenticate(credentials, request, context)); - } - } - } - public interface PagedRequest { @NotNull List next(@NotNull GithubConnection connection) throws IOException; diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnectionBuilder.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnectionBuilder.java new file mode 100644 index 000000000000..233b3154bcca --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnectionBuilder.java @@ -0,0 +1,156 @@ +/* + * Copyright 2000-2016 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.plugins.github.api; + +import com.intellij.util.net.IdeHttpClientHelpers; +import com.intellij.util.net.ssl.CertificateManager; +import org.apache.http.*; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.AuthSchemes; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.config.ConnectionConfig; +import org.apache.http.conn.ssl.X509HostnameVerifier; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicHeader; +import org.apache.http.protocol.HttpContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.github.util.GithubAuthData; +import org.jetbrains.plugins.github.util.GithubSettings; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +class GithubConnectionBuilder { + @NotNull private final GithubAuthData myAuth; + + public GithubConnectionBuilder(@NotNull GithubAuthData auth) { + myAuth = auth; + } + + @NotNull + public CloseableHttpClient createClient() { + HttpClientBuilder builder = HttpClients.custom(); + + builder + .setDefaultRequestConfig(createRequestConfig()) + .setDefaultConnectionConfig(createConnectionConfig()) + .setDefaultHeaders(createHeaders()) + .setSslcontext(CertificateManager.getInstance().getSslContext()) + .setHostnameVerifier((X509HostnameVerifier)CertificateManager.HOSTNAME_VERIFIER); + + setupCredentialsProvider(builder); + + return builder.build(); + } + + @NotNull + private RequestConfig createRequestConfig() { + RequestConfig.Builder builder = RequestConfig.custom(); + + int timeout = GithubSettings.getInstance().getConnectionTimeout(); + builder + .setConnectTimeout(timeout) + .setSocketTimeout(timeout); + + if (myAuth.isUseProxy()) { + IdeHttpClientHelpers.ApacheHttpClient4.setProxyForUrlIfEnabled(builder, myAuth.getHost()); + } + + return builder.build(); + } + + @NotNull + private ConnectionConfig createConnectionConfig() { + return ConnectionConfig.custom() + .setCharset(Consts.UTF_8) + .build(); + } + + + @NotNull + private CredentialsProvider setupCredentialsProvider(@NotNull HttpClientBuilder builder) { + CredentialsProvider provider = new BasicCredentialsProvider(); + // Basic authentication + GithubAuthData.BasicAuth basicAuth = myAuth.getBasicAuth(); + if (basicAuth != null) { + AuthScope authScope = getBasicAuthScope(); + + provider.setCredentials(authScope, new UsernamePasswordCredentials(basicAuth.getLogin(), basicAuth.getPassword())); + builder.addInterceptorFirst(new PreemptiveBasicAuthInterceptor(authScope)); + } + builder.setDefaultCredentialsProvider(provider); + + if (myAuth.isUseProxy()) { + IdeHttpClientHelpers.ApacheHttpClient4.setProxyCredentialsForUrlIfEnabled(provider, myAuth.getHost()); + } + + return provider; + } + + @NotNull + private AuthScope getBasicAuthScope() { + try { + URIBuilder builder = new URIBuilder(myAuth.getHost()); + return new AuthScope(builder.getHost(), builder.getPort(), AuthScope.ANY_REALM, AuthSchemes.BASIC); + } + catch (URISyntaxException e) { + return AuthScope.ANY; + } + } + + @NotNull + private Collection createHeaders() { + List
headers = new ArrayList<>(); + GithubAuthData.TokenAuth tokenAuth = myAuth.getTokenAuth(); + if (tokenAuth != null) { + headers.add(new BasicHeader("Authorization", "token " + tokenAuth.getToken())); + } + GithubAuthData.BasicAuth basicAuth = myAuth.getBasicAuth(); + if (basicAuth != null && basicAuth.getCode() != null) { + headers.add(new BasicHeader("X-GitHub-OTP", basicAuth.getCode())); + } + return headers; + } + + private static class PreemptiveBasicAuthInterceptor implements HttpRequestInterceptor { + @NotNull private final AuthScope myBasicAuthScope; + + public PreemptiveBasicAuthInterceptor(@NotNull AuthScope basicAuthScope) { + myBasicAuthScope = basicAuthScope; + } + + @Override + public void process(HttpRequest request, HttpContext context) throws HttpException, IOException { + CredentialsProvider provider = (CredentialsProvider)context.getAttribute(HttpClientContext.CREDS_PROVIDER); + Credentials credentials = provider.getCredentials(myBasicAuthScope); + if (credentials != null) { + request.addHeader(new BasicScheme(Consts.UTF_8).authenticate(credentials, request, context)); + } + } + } +} From 047ad30942c2ea1cb3297f7f727b7204ecc7b893 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 12 Sep 2016 14:42:14 +0300 Subject: [PATCH 14/24] IDEA-136797 IDEA-126276 github: respect "No proxy for" parameter `auth.getHost()` might be set without protocol (ex: github.com), in this case `new URI(auth.getHost()).getHost()` will return null. --- .../plugins/github/api/GithubConnection.java | 19 +++++++------------ .../github/api/GithubConnectionBuilder.java | 10 ++++++---- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java index aa14956c789d..659dc2d297ec 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java @@ -50,7 +50,7 @@ import static org.jetbrains.plugins.github.api.GithubApiUtil.fromJson; public class GithubConnection { private static final Logger LOG = GithubUtil.LOG; - @NotNull private final String myHost; + @NotNull private final String myApiURL; @NotNull private final CloseableHttpClient myClient; private final boolean myReusable; @@ -63,8 +63,8 @@ public class GithubConnection { } public GithubConnection(@NotNull GithubAuthData auth, boolean reusable) { - myHost = auth.getHost(); - myClient = new GithubConnectionBuilder(auth).createClient(); + myApiURL = GithubUrlUtil.getApiUrl(auth.getHost()); + myClient = new GithubConnectionBuilder(auth, myApiURL).createClient(); myReusable = reusable; } @@ -105,8 +105,8 @@ public class GithubConnection { } @NotNull - public String getHost() { - return myHost; + String getApiURL() { + return myApiURL; } public void abort() { @@ -121,17 +121,12 @@ public class GithubConnection { myClient.close(); } - @NotNull - private static String getRequestUrl(@NotNull String host, @NotNull String path) { - return GithubUrlUtil.getApiUrl(host) + path; - } - @NotNull private ResponsePage request(@NotNull String path, @Nullable String requestBody, @NotNull Collection
headers, @NotNull HttpVerb verb) throws IOException { - return doRequest(getRequestUrl(myHost, path), requestBody, headers, verb); + return doRequest(myApiURL + path, requestBody, headers, verb); } @NotNull @@ -331,7 +326,7 @@ public class GithubConnection { public List next(@NotNull GithubConnection connection) throws IOException { String url; if (myFirstRequest) { - url = getRequestUrl(connection.getHost(), myPath); + url = connection.getApiURL() + myPath; myFirstRequest = false; } else { diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnectionBuilder.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnectionBuilder.java index 233b3154bcca..660f69d70cb0 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnectionBuilder.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnectionBuilder.java @@ -47,9 +47,11 @@ import java.util.List; class GithubConnectionBuilder { @NotNull private final GithubAuthData myAuth; + @NotNull private final String myApiURL; - public GithubConnectionBuilder(@NotNull GithubAuthData auth) { + public GithubConnectionBuilder(@NotNull GithubAuthData auth, @NotNull String apiURL) { myAuth = auth; + myApiURL = apiURL; } @NotNull @@ -78,7 +80,7 @@ class GithubConnectionBuilder { .setSocketTimeout(timeout); if (myAuth.isUseProxy()) { - IdeHttpClientHelpers.ApacheHttpClient4.setProxyForUrlIfEnabled(builder, myAuth.getHost()); + IdeHttpClientHelpers.ApacheHttpClient4.setProxyForUrlIfEnabled(builder, myApiURL); } return builder.build(); @@ -106,7 +108,7 @@ class GithubConnectionBuilder { builder.setDefaultCredentialsProvider(provider); if (myAuth.isUseProxy()) { - IdeHttpClientHelpers.ApacheHttpClient4.setProxyCredentialsForUrlIfEnabled(provider, myAuth.getHost()); + IdeHttpClientHelpers.ApacheHttpClient4.setProxyCredentialsForUrlIfEnabled(provider, myApiURL); } return provider; @@ -115,7 +117,7 @@ class GithubConnectionBuilder { @NotNull private AuthScope getBasicAuthScope() { try { - URIBuilder builder = new URIBuilder(myAuth.getHost()); + URIBuilder builder = new URIBuilder(myApiURL); return new AuthScope(builder.getHost(), builder.getPort(), AuthScope.ANY_REALM, AuthSchemes.BASIC); } catch (URISyntaxException e) { From fadddf8526b0614abda309c01c1a667ec0353eae Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Mon, 12 Sep 2016 15:05:51 +0300 Subject: [PATCH 15/24] fix condition (thanks to Andrey) --- .../src/com/intellij/openapi/roots/impl/RootModelImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelImpl.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelImpl.java index d35d7ba66f8a..8d9e4a8f1b4b 100644 --- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelImpl.java +++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootModelImpl.java @@ -226,7 +226,7 @@ public class RootModelImpl extends RootModelBase implements ModifiableRootModel public LibraryOrderEntry addLibraryEntry(@NotNull Library library) { assertWritable(); final LibraryOrderEntry libraryOrderEntry = new LibraryOrderEntryImpl(library, this, myProjectRootManager); - if (libraryOrderEntry.isValid()) { + if (!libraryOrderEntry.isValid()) { LibraryEx libraryEx = ObjectUtils.tryCast(library, LibraryEx.class); boolean libraryDisposed = libraryEx != null ? libraryEx.isDisposed() : Disposer.isDisposed(library); throw new AssertionError("Invalid libraryOrderEntry, library: " + library From 9a3d10a2ad2b7548f166adb2a5ca46c4fab6e0ba Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 12 Sep 2016 15:43:14 +0300 Subject: [PATCH 16/24] EA-83281 - PIEAE: LeafPsiElement.invalid --- .../openapi/src/com/intellij/debugger/SourcePosition.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java b/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java index 315af2af34a2..0628fb94c4ae 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java +++ b/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java @@ -233,6 +233,10 @@ public abstract class SourcePosition implements Navigatable{ public PsiElement compute() { PsiElement rootElement = psiFile; + if (!psiFile.isValid()) { + return null; + } + List allFiles = psiFile.getViewProvider().getAllFiles(); if (allFiles.size() > 1) { // jsp & gsp PsiClassOwner owner = ContainerUtil.findInstance(allFiles, PsiClassOwner.class); From 1f3c96cdbdf6006b8024850e2bac9ad4140f9153 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 12 Sep 2016 15:03:06 +0200 Subject: [PATCH 17/24] low memory flusher doesn't wait for write lock if it can not be taken at the moment (WEB-23202) --- .../com/intellij/util/indexing/MapReduceIndex.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java index 53577b44493b..dad726119b41 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java @@ -82,11 +82,13 @@ public class MapReduceIndex implements UpdatableIndex)myStorage).clearCaches(); - } finally { - getWriteLock().unlock(); + Lock writeLock = getWriteLock(); + if (writeLock.tryLock()) { + try { + ((MemoryIndexStorage)myStorage).clearCaches(); + } finally { + writeLock.unlock(); + } } } flush(); From 1591b2730fea142c6737968ae0fb1a0de49da885 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 12 Sep 2016 13:07:35 +0200 Subject: [PATCH 18/24] fix SoftWrapApplianceOnDocumentModificationTest by invoking "line comment" action even though it's disabled --- .../mapping/SoftWrapApplianceOnDocumentModificationTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java index f24f26e3ef94..64030d0ddfb5 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java @@ -16,6 +16,7 @@ package com.intellij.openapi.editor.impl.softwrap.mapping; import com.intellij.codeInsight.folding.CodeFoldingManager; +import com.intellij.codeInsight.generation.actions.CommentByLineCommentAction; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.ex.DocumentEx; @@ -672,7 +673,7 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorT CaretModel caretModel = myEditor.getCaretModel(); caretModel.moveToOffset(text.indexOf("2.") + 2); - lineComment(); + new CommentByLineCommentAction().actionPerformedImpl(getProject(), getEditor()); assertEquals(myEditor.offsetToLogicalPosition(text.indexOf("3.") + 2), caretModel.getLogicalPosition()); } From d29b582d91f33113fe0d805af67dc8a6fcaceb41 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 12 Sep 2016 13:30:18 +0200 Subject: [PATCH 19/24] live template: when a lookup item is inserted so that the caret is in the next variable, move to that variable --- .../codeInsight/template/impl/TemplateState.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java index 2eb9ba6712aa..2e9f250f12be 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java @@ -122,8 +122,13 @@ public class TemplateState implements Disposable { myLookupListener = new LookupAdapter() { @Override public void itemSelected(LookupEvent event) { - if (isCaretOutsideCurrentSegment() && !isCaretInsideNextVariable()) { - gotoEnd(true); + if (isCaretOutsideCurrentSegment()) { + if (isCaretInsideNextVariable()) { + nextTab(); + } + else { + gotoEnd(true); + } } } }; From f03580a0759310b53aabbc1f5c306a7efed0d313 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 12 Sep 2016 15:07:28 +0200 Subject: [PATCH 20/24] java completion: suggest inaccessible constructors of anonymous classes --- .../JavaConstructorCallElement.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaConstructorCallElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaConstructorCallElement.java index ea9b4f7178d8..4acc787e7b49 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaConstructorCallElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaConstructorCallElement.java @@ -26,7 +26,7 @@ import com.intellij.psi.impl.source.resolve.JavaResolveUtil; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.containers.JBIterable; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.Collections; @@ -92,17 +92,23 @@ public class JavaConstructorCallElement extends JavaMethodCallElement { static List wrap(@NotNull LookupElement classItem, @NotNull PsiClass psiClass, @NotNull PsiElement position, @NotNull Supplier type) { if (Registry.is("java.completion.show.constructors") && isConstructorCallPlace(position)) { - PsiMethod[] constructors = psiClass.getConstructors(); - if (constructors.length > 0) { - return JBIterable.of(constructors). - filter(c -> JavaResolveUtil.isAccessible(c, psiClass, c.getModifierList(), position, null, null)). - map(c -> new JavaConstructorCallElement(classItem, c, type)). - toList(); + List constructors = ContainerUtil.filter(psiClass.getConstructors(), c -> shouldSuggestConstructor(psiClass, position, c)); + if (!constructors.isEmpty()) { + return ContainerUtil.map(constructors, c -> new JavaConstructorCallElement(classItem, c, type)); } } return Collections.singletonList(classItem); } + private static boolean shouldSuggestConstructor(@NotNull PsiClass psiClass, @NotNull PsiElement position, PsiMethod constructor) { + return JavaResolveUtil.isAccessible(constructor, psiClass, constructor.getModifierList(), position, null, null) || + willBeAccessibleInAnonymous(psiClass, constructor); + } + + private static boolean willBeAccessibleInAnonymous(@NotNull PsiClass psiClass, PsiMethod constructor) { + return !constructor.hasModifierProperty(PsiModifier.PRIVATE) && psiClass.hasModifierProperty(PsiModifier.ABSTRACT); + } + private static boolean isConstructorCallPlace(@NotNull PsiElement position) { return CachedValuesManager.getCachedValue(position, () -> { boolean result = JavaClassNameCompletionContributor.AFTER_NEW.accepts(position) && From 0028bc789aca1fb6833e41181171b8867e5fcb8f Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 12 Sep 2016 15:08:52 +0200 Subject: [PATCH 21/24] java method argument completion: move the caret outside the parentheses at the end, remove autocompletion --- .../completion/JavaMethodCallElement.java | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java index 8f93eeec1ceb..be53fc0cd139 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java @@ -21,16 +21,15 @@ import com.intellij.codeInsight.lookup.impl.JavaElementLookupRenderer; import com.intellij.codeInsight.template.Template; import com.intellij.codeInsight.template.TemplateManager; import com.intellij.codeInsight.template.impl.ConstantNode; -import com.intellij.codeInsight.template.impl.MacroCallNode; import com.intellij.codeInsight.template.impl.TemplateManagerImpl; import com.intellij.codeInsight.template.impl.TemplateState; -import com.intellij.codeInsight.template.macro.CompleteMacro; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.ClassConditionKey; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; @@ -176,17 +175,11 @@ public class JavaMethodCallElement extends LookupItem implements Type } context.commitDocument(); - if (hasParams && context.getCompletionChar() != Lookup.COMPLETE_STATEMENT_SELECT_CHAR && Registry.is("java.completion.argument.live.template") && isArgumentListEmpty(context)) { + if (hasParams && context.getCompletionChar() != Lookup.COMPLETE_STATEMENT_SELECT_CHAR && Registry.is("java.completion.argument.live.template")) { startArgumentLiveTemplate(context, method); } } - private static boolean isArgumentListEmpty(InsertionContext context) { - PsiCallExpression call = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiCallExpression.class, false); - PsiExpressionList argList = call == null ? null : call.getArgumentList(); - return argList != null && argList.getExpressions().length == 0; - } - private void importOrQualify(Document document, PsiFile file, PsiMethod method, int startOffset) { if (willBeImported()) { final PsiReferenceExpression ref = PsiTreeUtil.findElementOfClassAtOffset(file, startOffset, PsiReferenceExpression.class, false); @@ -200,20 +193,45 @@ public class JavaMethodCallElement extends LookupItem implements Type } public static final Key ARGUMENT_TEMPLATE_ACTIVE = Key.create("ARGUMENT_TEMPLATE_ACTIVE"); - private void startArgumentLiveTemplate(InsertionContext context, PsiMethod method) { - TemplateManager manager = TemplateManager.getInstance(method.getProject()); - Template template = manager.createTemplate("", ""); + @NotNull + private static Template createArgTemplate(PsiMethod method, + int caretOffset, + PsiExpressionList argList, + TextRange argRange) { + Template template = TemplateManager.getInstance(method.getProject()).createTemplate("", ""); + template.addTextSegment(argList.getText().substring(0, caretOffset - argRange.getStartOffset())); PsiParameter[] parameters = method.getParameterList().getParameters(); for (int i = 0; i < parameters.length; i++) { if (i > 0) { template.addTextSegment(", "); } String name = StringUtil.notNullize(parameters[i].getName()); - template.addVariable(name, new MacroCallNode(new CompleteMacro()), new ConstantNode(name), true); + template.addVariable(name, new ConstantNode(name), new ConstantNode(name), true); + } + template.addTextSegment(argList.getText().substring(caretOffset - argRange.getStartOffset(), argList.getTextLength())); + template.addEndVariable(); + return template; + } + + private void startArgumentLiveTemplate(InsertionContext context, PsiMethod method) { + Editor editor = context.getEditor(); + + PsiCallExpression call = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), PsiCallExpression.class, false); + PsiExpressionList argList = call == null ? null : call.getArgumentList(); + if (argList == null || argList.getExpressions().length > 0) { + return; } - Editor editor = context.getEditor(); - manager.startTemplate(editor, template); + TextRange argRange = argList.getTextRange(); + int caretOffset = editor.getCaretModel().getOffset(); + if (!argRange.contains(caretOffset)) { + return; + } + + Template template = createArgTemplate(method, caretOffset, argList, argRange); + + context.getDocument().deleteString(argRange.getStartOffset(), argRange.getEndOffset()); + TemplateManager.getInstance(method.getProject()).startTemplate(editor, template); TemplateState templateState = TemplateManagerImpl.getTemplateState(editor); if (templateState == null) return; From abf0b206437ac48258fa2b2325b7c748c2a93933 Mon Sep 17 00:00:00 2001 From: Anton Tarasov Date: Mon, 12 Sep 2016 16:15:31 +0300 Subject: [PATCH 22/24] [macOS] Mind dock icon size when drawing "Ok" icon on it The "Ok" icon assumes 128x128 dock icon size. For the debug IDEA the dock icon is 512x512. So, the "ok" icon should be scaled appropriately before drawing. --- platform/platform-impl/src/com/intellij/ui/AppIcon.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ui/AppIcon.java b/platform/platform-impl/src/com/intellij/ui/AppIcon.java index d2534cbd2886..c3c17aaa044e 100644 --- a/platform/platform-impl/src/com/intellij/ui/AppIcon.java +++ b/platform/platform-impl/src/com/intellij/ui/AppIcon.java @@ -26,6 +26,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.AppIconScheme; import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.WindowManager; +import com.intellij.util.IconUtil; import com.intellij.util.ui.ImageUtil; import com.intellij.util.ui.UIUtil; import org.apache.sanselan.ImageWriteException; @@ -256,7 +257,12 @@ public abstract class AppIcon { if (visible) { Icon okIcon = AllIcons.Mac.AppIconOk512; - int x = img.myImg.getWidth() - okIcon.getIconWidth(); + int myImgWidth = img.myImg.getWidth(); + if (myImgWidth != 128) { + okIcon = IconUtil.scale(okIcon, myImgWidth / 128); + } + + int x = myImgWidth - okIcon.getIconWidth(); int y = 0; okIcon.paintIcon(JOptionPane.getRootFrame(), img.myG2d, x, y); From aa251132860ff81f5519352ec06589fdf2022b37 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Mon, 12 Sep 2016 16:41:33 +0300 Subject: [PATCH 23/24] ensure the focused editor in getData --- .../console/LanguageConsoleImpl.java | 45 +++++++++---------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index 6f47e5b79ef9..3ed2ae188039 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -27,6 +27,7 @@ import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.EmptyAction; import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.command.undo.UndoUtil; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.colors.EditorColorsManager; @@ -45,7 +46,6 @@ import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl; import com.intellij.openapi.fileTypes.SyntaxHighlighter; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.registry.Registry; @@ -262,12 +262,9 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons } private void setPromptInner(@Nullable final String prompt) { - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - if (!myConsoleEditor.isDisposed()) { - myConsoleEditor.setPrefixTextAndAttributes(prompt, myPromptAttributes.getAttributes()); - } + UIUtil.invokeAndWaitIfNeeded((Runnable)() -> { + if (!myConsoleEditor.isDisposed()) { + myConsoleEditor.setPrefixTextAndAttributes(prompt, myPromptAttributes.getAttributes()); } }); } @@ -453,18 +450,7 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons @Nullable @Override public Object getData(@NonNls String dataId) { - Object data = super.getData(dataId); - if (data != null) { - return data; - } - else if (OpenFileDescriptor.NAVIGATE_IN_EDITOR.is(dataId)) { - return myConsoleEditor; - } - else if (getProject().isInitialized()) { - Caret caret = myConsoleEditor.getCaretModel().getCurrentCaret(); - return FileEditorManagerEx.getInstanceEx(getProject()).getData(dataId, myConsoleEditor, caret); - } - return null; + return super.getData(dataId); } private void installEditorFactoryListener() { @@ -555,12 +541,7 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons @NotNull public PsiFile getFile() { - return ApplicationManager.getApplication().runReadAction(new Computable() { - @Override - public PsiFile compute() { - return PsiUtilCore.getPsiFile(project, virtualFile); - } - }); + return ReadAction.compute(() -> PsiUtilCore.getPsiFile(project, virtualFile)); } @NotNull @@ -591,12 +572,26 @@ public class LanguageConsoleImpl extends ConsoleViewImpl implements LanguageCons EditorSettings editorSettings = editor.getSettings(); editorSettings.setAdditionalLinesCount(1); editorSettings.setAdditionalColumnsCount(1); + + DataManager.registerDataProvider(editor.getComponent(), (dataId) -> getEditorData(editor, dataId)); } @NotNull PsiFile getFileSafe() { return file == null || !file.isValid() ? file = getFile() : file; } + + @Nullable + protected Object getEditorData(@NotNull EditorEx editor, String dataId) { + if (OpenFileDescriptor.NAVIGATE_IN_EDITOR.is(dataId)) { + return editor; + } + else if (project.isInitialized()) { + Caret caret = editor.getCaretModel().getCurrentCaret(); + return FileEditorManagerEx.getInstanceEx(project).getData(dataId, editor, caret); + } + return null; + } } private class MyLayout extends AbstractLayoutManager { From c8c490d7dd738ced4326a6de2ad6d66a1596a605 Mon Sep 17 00:00:00 2001 From: "Gregory.Shrago" Date: Mon, 12 Sep 2016 16:43:53 +0300 Subject: [PATCH 24/24] treat HOST_EDITOR like EDITOR in doGetData --- .../src/com/intellij/ide/impl/DataManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ide/impl/DataManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/impl/DataManagerImpl.java index 655127e2d907..941d278d87e1 100644 --- a/platform/platform-impl/src/com/intellij/ide/impl/DataManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/ide/impl/DataManagerImpl.java @@ -386,7 +386,7 @@ public class DataManagerImpl extends DataManager { if (PlatformDataKeys.MODALITY_STATE.is(dataId)) { return component != null ? ModalityState.stateForComponent(component) : ModalityState.NON_MODAL; } - if (CommonDataKeys.EDITOR.is(dataId)) { + if (CommonDataKeys.EDITOR.is(dataId) || CommonDataKeys.HOST_EDITOR.is(dataId)) { Editor editor = (Editor)((DataManagerImpl)DataManager.getInstance()).getData(dataId, component); return validateEditor(editor); }