From d8520bc73004e3cfa62aeba1ca528e11da061a26 Mon Sep 17 00:00:00 2001 From: Vladimir Plyashkun Date: Thu, 6 Apr 2017 11:00:52 +0300 Subject: [PATCH 001/111] CPP-9383 Add an internal action to get actual clang-tidy command line --- platform/util/resources/misc/registry.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 79d3592bcafa..592be20f3912 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -842,6 +842,7 @@ hg4idea.process.ignored.description=Process and highlight mercurial ignored file Switching on this option may lead to some performance problems. cidr.show.compiler.info=false +cidr.show.clangtidy.info=false cidr.cygwin.cmakePermissionsFix=true cidr.cygwin.cmakePermissionsFix.description=Update permissions for the bin/ folder inside the installed IDE so that the bundled CMake could run cidr.max.intellisense.file.length=500000 From 5c556d9db0733b1cd56bfc88e9f7747c8e390ec6 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 6 Apr 2017 15:53:42 +0200 Subject: [PATCH 002/111] [ui] exact check for update timestamp in tooltip --- .../openapi/updateSettings/impl/UpdateChecker.kt | 10 ++++------ .../impl/UpdateSettingsConfigurable.java | 10 ++++++++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.kt b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.kt index 6c7c8cfac8eb..5f2d4b8ff499 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.kt +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -120,11 +120,7 @@ object UpdateChecker { indicator?.text = IdeBundle.message("updates.checking.platform") val result = checkPlatformUpdate(updateSettings) - - if (manualCheck && result.state == UpdateStrategy.State.LOADED) { - UpdateSettings.getInstance().saveLastCheckedInfo() - } - else if (result.state == UpdateStrategy.State.CONNECTION_ERROR) { + if (result.state == UpdateStrategy.State.CONNECTION_ERROR) { val e = result.error if (e != null) LOG.debug(e) showErrorMessage(manualCheck, IdeBundle.message("updates.error.connection.failed", e?.message ?: "internal error")) @@ -151,6 +147,8 @@ object UpdateChecker { // show result + UpdateSettings.getInstance().saveLastCheckedInfo() + ApplicationManager.getApplication().invokeLater({ showUpdateResult(project, result, updateSettings, updatedPlugins, incompatiblePlugins, externalUpdates, !fromSettings, manualCheck) callback?.setDone() diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.java index 379079825f10..38874f25e088 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettingsConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -210,7 +210,13 @@ public class UpdateSettingsConfigurable extends BaseConfigurable implements Sear private void updateLastCheckedLabel() { long time = mySettings.getLastTimeChecked(); - myLastCheckedDate.setText(time == 0 ? IdeBundle.message("updates.last.check.never") : DateFormatUtil.formatPrettyDateTime(time)); + if (time <= 0) { + myLastCheckedDate.setText(IdeBundle.message("updates.last.check.never")); + } + else { + myLastCheckedDate.setText(DateFormatUtil.formatPrettyDateTime(time)); + myLastCheckedDate.setToolTipText(DateFormatUtil.formatDate(time) + ' ' + DateFormatUtil.formatTimeWithSeconds(time)); + } } public ChannelStatus getSelectedChannelType() { From e02e84f9aeb1862ead483fefea8efe47ca97d7eb Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 6 Apr 2017 17:58:52 +0200 Subject: [PATCH 003/111] [ui] corrects "check for updates" action name on the welcome screen --- platform/platform-resources/src/idea/PlatformActions.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml index 8f6cde011eac..ebff8b608a14 100644 --- a/platform/platform-resources/src/idea/PlatformActions.xml +++ b/platform/platform-resources/src/idea/PlatformActions.xml @@ -634,7 +634,7 @@ - + From c970aac1a2236f35441b3ebeee68d7722287272b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20C=C3=A9bron?= Date: Thu, 6 Apr 2017 18:14:38 +0200 Subject: [PATCH 004/111] [devkit] UndesirableClassUsageInspection -> UAST --- plugins/devkit/resources/META-INF/plugin.xml | 2 +- .../UndesirableClassUsageInspection.java | 49 +++++++++++-------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml index 0800326f69b3..a2f1e9a96acb 100644 --- a/plugins/devkit/resources/META-INF/plugin.xml +++ b/plugins/devkit/resources/META-INF/plugin.xml @@ -86,7 +86,7 @@ level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.InspectionMappingConsistencyInspection"/> - diff --git a/plugins/devkit/src/inspections/internal/UndesirableClassUsageInspection.java b/plugins/devkit/src/inspections/internal/UndesirableClassUsageInspection.java index b2f339d40480..42c0d9b9fbb3 100644 --- a/plugins/devkit/src/inspections/internal/UndesirableClassUsageInspection.java +++ b/plugins/devkit/src/inspections/internal/UndesirableClassUsageInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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,22 +19,29 @@ import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.openapi.application.QueryExecutorBase; import com.intellij.openapi.ui.ComboBox; -import com.intellij.psi.*; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.util.PsiTypesUtil; +import com.intellij.uast.UastVisitorAdapter; import com.intellij.ui.components.JBList; import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.components.JBTabbedPane; import com.intellij.ui.table.JBTable; import com.intellij.ui.treeStructure.Tree; +import com.intellij.util.ObjectUtils; import com.intellij.util.QueryExecutor; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.devkit.inspections.DevKitInspectionBase; +import org.jetbrains.idea.devkit.inspections.DevKitUastInspectionBase; +import org.jetbrains.uast.UCallExpression; +import org.jetbrains.uast.UastCallKind; +import org.jetbrains.uast.visitor.AbstractUastVisitor; import javax.swing.*; import java.awt.image.BufferedImage; import java.util.Map; -public class UndesirableClassUsageInspection extends DevKitInspectionBase { +public class UndesirableClassUsageInspection extends DevKitUastInspectionBase { private static final Map CLASSES = ContainerUtil.immutableMapBuilder() .put(JList.class.getName(), JBList.class.getName()) @@ -50,23 +57,23 @@ public class UndesirableClassUsageInspection extends DevKitInspectionBase { @Override @NotNull public PsiElementVisitor buildInternalVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { - return new JavaElementVisitor() { + return new UastVisitorAdapter(new AbstractUastVisitor() { @Override - public void visitNewExpression(PsiNewExpression expression) { - PsiJavaCodeReferenceElement ref = expression.getClassReference(); - if (ref == null) return; - - PsiElement res = ref.resolve(); - if (res == null) return; - - String name = ((PsiClass)res).getQualifiedName(); - if (name == null) return; - - String replacement = CLASSES.get(name); - if (replacement == null) return; - - holder.registerProblem(expression, "Please use '" + replacement + "' instead", ProblemHighlightType.LIKE_DEPRECATED); + public boolean visitCallExpression(@NotNull UCallExpression expression) { + if (expression.getKind() == UastCallKind.CONSTRUCTOR_CALL) { + final PsiClass psiClass = PsiTypesUtil.getPsiClass(expression.getReturnType()); + if (psiClass != null) { + final String name = psiClass.getQualifiedName(); + String replacement = CLASSES.get(name); + if (replacement != null) { + holder.registerProblem(ObjectUtils.assertNotNull(expression.getPsi()), + "Please use '" + replacement + "' instead", + ProblemHighlightType.LIKE_DEPRECATED); + } + } + } + return true; } - }; + }); } -} +} \ No newline at end of file From c7eadcb5fb2c5ffb866df2b3f9b9b3d56f438880 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Thu, 6 Apr 2017 18:59:31 +0300 Subject: [PATCH 005/111] diff: high resolution icons for frame windows --- .../intellij/diff/impl/DiffWindowBase.java | 3 +-- .../src/com/intellij/diff/util/DiffUtil.java | 14 ++++++++++++ platform/icons/src/diff_frame128.png | Bin 0 -> 633 bytes platform/icons/src/diff_frame16.png | Bin 0 -> 155 bytes platform/icons/src/diff_frame32.png | Bin 0 -> 217 bytes platform/icons/src/diff_frame64.png | Bin 0 -> 363 bytes platform/icons/src/icon-robots.txt | 1 + .../integration/ui/views/HistoryDialog.java | 4 ++-- .../intellij/openapi/ui/WindowWrapper.java | 3 ++- .../com/intellij/openapi/ui/FrameWrapper.java | 20 ++++++++++-------- .../openapi/ui/WindowWrapperBuilder.java | 7 +++--- 11 files changed, 35 insertions(+), 17 deletions(-) create mode 100644 platform/icons/src/diff_frame128.png create mode 100644 platform/icons/src/diff_frame16.png create mode 100644 platform/icons/src/diff_frame32.png create mode 100644 platform/icons/src/diff_frame64.png create mode 100644 platform/icons/src/icon-robots.txt diff --git a/platform/diff-impl/src/com/intellij/diff/impl/DiffWindowBase.java b/platform/diff-impl/src/com/intellij/diff/impl/DiffWindowBase.java index 0b72007c6928..2618a34113de 100644 --- a/platform/diff-impl/src/com/intellij/diff/impl/DiffWindowBase.java +++ b/platform/diff-impl/src/com/intellij/diff/impl/DiffWindowBase.java @@ -22,7 +22,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.WindowWrapper; import com.intellij.openapi.ui.WindowWrapperBuilder; import com.intellij.openapi.util.Disposer; -import com.intellij.util.ImageLoader; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -58,7 +57,7 @@ public abstract class DiffWindowBase { myProcessor.updateRequest(); }) .build(); - myWrapper.setImage(ImageLoader.loadFromResource("/diff/Diff.png")); + myWrapper.setImages(DiffUtil.DIFF_FRAME_ICONS); Disposer.register(myWrapper, myProcessor); } diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java index 097af8c4fc8a..481c376804d1 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java @@ -88,6 +88,7 @@ import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBLabel; import com.intellij.util.ArrayUtil; import com.intellij.util.DocumentUtil; +import com.intellij.util.ImageLoader; import com.intellij.util.LineSeparator; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; @@ -113,6 +114,19 @@ public class DiffUtil { @NotNull public static final String DIFF_CONFIG = "diff.xml"; public static final int TITLE_GAP = JBUI.scale(2); + public static final List DIFF_FRAME_ICONS = loadDiffFrameImages(); + + + @NotNull + private static List loadDiffFrameImages() { + return ContainerUtil.list( + ImageLoader.loadFromResource("/diff_frame16.png"), + ImageLoader.loadFromResource("/diff_frame32.png"), + ImageLoader.loadFromResource("/diff_frame64.png"), + ImageLoader.loadFromResource("/diff_frame128.png") + ); + } + // // Editor // diff --git a/platform/icons/src/diff_frame128.png b/platform/icons/src/diff_frame128.png new file mode 100644 index 0000000000000000000000000000000000000000..7fe30c2947391f6b13c569063e50d583c5e2910e GIT binary patch literal 633 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n4~>j978H@y}5hP^Kb$~+ruRt$E$)^+&47eV7;O#qAobs z$@Pog(cG3G^AC&I`kj={`uqI0eIM!dwOZ=-q-CM1o|9BOCk3tgeeXcg*MB=t);An( zUd%iH!{Y00!u^eJ7#JKFI2afe7+4P2msb|1PEBF>Ud}JDYF4KeE&n9g=8O~eE z!r{)~V8O(2NRUCGkD;M}g`q{cz|MiaY1yQFk*WXZ9sTy&!ivd4h=GBTK>!Q!k%Iw? z2@DD{jlqZ5TnvuA+Gif{Yj<<|x<8gx&d=vKfTE}YXcChHC_Ys@_x}<~V7PrW+GN$i Ru(=FC;OXk;vd$@?2>|tS=V|}| literal 0 HcmV?d00001 diff --git a/platform/icons/src/diff_frame16.png b/platform/icons/src/diff_frame16.png new file mode 100644 index 0000000000000000000000000000000000000000..b86600dd917b4e77b77d1ad22f918932612261b7 GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`NuDl_Ar-fh6BdY7e0=q_K4(T_ zBQN{0M289&o>aC5m5IEHrx{Y5J4_gMD@{-gF->^1WaX1;#wC(hy;WG0e2fFx7Pu>K zN;_lXD@F$G@qC`(fkXJAn4pYbg2i{mk%Z492SelF{r5}E-2 C#4`i{ literal 0 HcmV?d00001 diff --git a/platform/icons/src/diff_frame32.png b/platform/icons/src/diff_frame32.png new file mode 100644 index 0000000000000000000000000000000000000000..65bb77966fd35ff56928b139cec5c4d441ec5daa GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ1)eUBAr-fh6C_wO9voeL{lDiy z9-bVPM+;vxeCU|bSjym`tml5=EaMIt$8h$9VwStI4evO#tQt(36Z#|!*bm4U7Rfp^ zYe;->@wl5~QF!S}qjrbGw8v#Kz1>MOo`#e*Oxy3H*$y?79@lSwAfCjGyf!A8hl>@w9^s-MN!mBy+3`d zIYKy89smFUfCRwleDMu1Tx<`5DS$l)<^XaLOakN}m<32hFb$A`U>;x#!3Dq?f*XJ( z1cd-~|Ii%49l#vHCBPKHEx?EX0Ji`SL0*GQgqRAm7|I&g+uiSScnF{OJ3|eTF?YJhxr^Qvb#ifqRtKArp{9Zui))-%m004kZ0E(ha*B4wjjw@Q=v916B002ov JPDHLkV1oPaj#K~u literal 0 HcmV?d00001 diff --git a/platform/icons/src/icon-robots.txt b/platform/icons/src/icon-robots.txt new file mode 100644 index 000000000000..e9a17d2af1c5 --- /dev/null +++ b/platform/icons/src/icon-robots.txt @@ -0,0 +1 @@ +skip: diff_frame* \ No newline at end of file diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/HistoryDialog.java b/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/HistoryDialog.java index 6611ccfc4b4c..ddc45b1f09b6 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/HistoryDialog.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/HistoryDialog.java @@ -20,6 +20,7 @@ import com.intellij.CommonBundle; import com.intellij.diff.contents.DiffContent; import com.intellij.diff.requests.ContentDiffRequest; import com.intellij.diff.requests.SimpleDiffRequest; +import com.intellij.diff.util.DiffUtil; import com.intellij.history.core.LocalHistoryFacade; import com.intellij.history.integration.IdeaGateway; import com.intellij.history.integration.LocalHistoryBundle; @@ -54,7 +55,6 @@ import com.intellij.ui.*; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBLayeredPane; import com.intellij.util.Consumer; -import com.intellij.util.ImageLoader; import com.intellij.util.ui.AbstractLayoutManager; import com.intellij.util.ui.AnimatedIcon; import com.intellij.util.ui.AsyncProcessIcon; @@ -98,7 +98,7 @@ public abstract class HistoryDialog extends FrameW setProject(project); setDimensionKey(getPropertiesKey()); - setImage(ImageLoader.loadFromResource("/diff/Diff.png")); + setImages(DiffUtil.DIFF_FRAME_ICONS); closeOnEsc(); if (doInit) init(); diff --git a/platform/platform-api/src/com/intellij/openapi/ui/WindowWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/WindowWrapper.java index 9baa58dd63d1..7455b9aa6982 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/WindowWrapper.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/WindowWrapper.java @@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; +import java.util.List; public interface WindowWrapper extends Disposable { enum Mode {FRAME, MODAL, NON_MODAL} @@ -27,7 +28,7 @@ public interface WindowWrapper extends Disposable { void setTitle(@Nullable String title); - void setImage(@Nullable Image image); + void setImages(@Nullable List images); void close(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java b/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java index ca7a39ec6b37..6a571575964e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/FrameWrapper.java @@ -24,7 +24,6 @@ import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.ex.ActionManagerEx; import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.actionSystem.impl.MouseGestureManager; -import com.intellij.openapi.application.impl.ApplicationInfoImpl; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.project.ProjectManagerAdapter; @@ -45,7 +44,6 @@ import com.intellij.ui.AppUIUtil; import com.intellij.ui.BalloonLayout; import com.intellij.ui.FocusTrackback; import com.intellij.ui.FrameState; -import com.intellij.util.ImageLoader; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.ImageUtil; import com.intellij.util.ui.UIUtil; @@ -57,6 +55,8 @@ import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.File; +import java.util.Collections; +import java.util.List; import java.util.Map; public class FrameWrapper implements Disposable, DataProvider { @@ -65,7 +65,7 @@ public class FrameWrapper implements Disposable, DataProvider { private JComponent myComponent = null; private JComponent myPreferredFocus = null; private String myTitle = ""; - private Image myImage = ImageLoader.loadFromResource(ApplicationInfoImpl.getShadowInstance().getIconUrl()); + private List myImages = null; private boolean myCloseOnEsc = false; private Window myFrame; private final Map myDataMap = ContainerUtil.newHashMap(); @@ -81,7 +81,6 @@ public class FrameWrapper implements Disposable, DataProvider { protected StatusBar myStatusBar; private boolean myShown; private boolean myIsDialog; - private boolean myImageWasChanged; public FrameWrapper(Project project) { this(project, null); @@ -175,9 +174,9 @@ public class FrameWrapper implements Disposable, DataProvider { } else { ((JDialog)frame).setTitle(myTitle); } - if (myImageWasChanged && myImage != null) { + if (myImages != null) { // unwrap the image before setting as frame's icon - frame.setIconImage(ImageUtil.toBufferedImage(myImage)); + frame.setIconImages(ContainerUtil.map(myImages, ImageUtil::toBufferedImage)); } else { AppUIUtil.updateWindowIcon(myFrame); @@ -230,7 +229,7 @@ public class FrameWrapper implements Disposable, DataProvider { myFocusedCallback = null; myFocusTrackback = null; myComponent = null; - myImage = null; + myImages = null; myDisposed = true; if (statusBar != null) { @@ -333,8 +332,11 @@ public class FrameWrapper implements Disposable, DataProvider { } public void setImage(Image image) { - myImageWasChanged = true; - myImage = image; + setImages(image != null ? Collections.singletonList(image) : Collections.emptyList()); + } + + public void setImages(List images) { + myImages = images; } protected void loadFrameState() { diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/WindowWrapperBuilder.java b/platform/platform-impl/src/com/intellij/openapi/ui/WindowWrapperBuilder.java index 96e25cef9497..39ff610194be 100644 --- a/platform/platform-impl/src/com/intellij/openapi/ui/WindowWrapperBuilder.java +++ b/platform/platform-impl/src/com/intellij/openapi/ui/WindowWrapperBuilder.java @@ -14,6 +14,7 @@ import javax.swing.border.Border; import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.util.List; public class WindowWrapperBuilder { @NotNull private final Mode myMode; @@ -170,7 +171,7 @@ public class WindowWrapperBuilder { } @Override - public void setImage(@Nullable Image image) { + public void setImages(@Nullable List images) { } @Override @@ -305,8 +306,8 @@ public class WindowWrapperBuilder { } @Override - public void setImage(@Nullable Image image) { - myFrame.setImage(image); + public void setImages(@Nullable List images) { + myFrame.setImages(images); } @Override From 69914f5aafc448d6e54bf5dc449d294308b8a345 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Thu, 6 Apr 2017 19:10:07 +0300 Subject: [PATCH 006/111] External dependencies: cleanup broken symlink while unpacking jdk 1.6 --- build/dependencies/setupJdk.gradle | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/build/dependencies/setupJdk.gradle b/build/dependencies/setupJdk.gradle index 8736f2627f21..dd9ae49fe6c9 100644 --- a/build/dependencies/setupJdk.gradle +++ b/build/dependencies/setupJdk.gradle @@ -120,8 +120,20 @@ task setupJdk16(dependsOn: configurations.jdk16) { doLast { logger.info("Setting up JDK 1.6 to compile") unpackJdk(jdkArchive.call(), outputDir) + deleteBrokenSymlink(outputDir) } } + +// Gradle dies on tring to process broken links: https://issues.gradle.org/browse/GRADLE-1843 +private void deleteBrokenSymlink(def outputDir) { + if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) { + def pluginJar = file("$outputDir/Home/lib/plugin.jar") + if (!pluginJar.exists()) { + pluginJar.delete() + } + } +} + setupJdk16.onlyIf { inJetBrainsNetwork } def intellijProjectDir() { From e5b450372ad7759d1ea26ccb13deb8d31d9b799e Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 6 Apr 2017 18:17:04 +0200 Subject: [PATCH 007/111] invalidate injected PSI without retrieving its host smart pointer PSI --- .../tree/injected/InjectedLanguageUtil.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java index 411ebbed370e..42da2e201538 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/tree/injected/InjectedLanguageUtil.java @@ -456,16 +456,13 @@ public class InjectedLanguageUtil { DebugUtil.finishPsiModification(); } - PsiElement context = InjectedLanguageManager.getInstance(injected.getProject()).getInjectionHost(injected); - PsiFile hostFile; - if (context != null) { - hostFile = context.getContainingFile(); - } - else { - VirtualFile delegate = virtualFile.getDelegate(); - hostFile = delegate.isValid() ? psiManagerEx.findFile(delegate) : null; - } - if (hostFile != null) { + VirtualFile delegate = virtualFile.getDelegate(); + if (!delegate.isValid()) return; + + FileViewProvider viewProvider = psiManagerEx.getFileManager().findCachedViewProvider(delegate); + if (!(viewProvider instanceof SingleRootFileViewProvider)) return; + + for (PsiFile hostFile : ((SingleRootFileViewProvider)viewProvider).getCachedPsiFiles()) { // modification of cachedInjectedDocuments must be under PsiLock synchronized (InjectedLanguageManagerImpl.ourInjectionPsiLock) { List cachedInjectedDocuments = getCachedInjectedDocuments(hostFile); From c96866a6366694831750e1e0577ce660d8b52006 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Thu, 6 Apr 2017 19:27:29 +0300 Subject: [PATCH 008/111] IDEA-171084 Code completion popup in front of other widows we should close all popups if a modal dialog is shown --- .../platform-impl/src/com/intellij/ide/IdePopupManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/ide/IdePopupManager.java b/platform/platform-impl/src/com/intellij/ide/IdePopupManager.java index c310bb074b63..53951e39b779 100644 --- a/platform/platform-impl/src/com/intellij/ide/IdePopupManager.java +++ b/platform/platform-impl/src/com/intellij/ide/IdePopupManager.java @@ -79,6 +79,9 @@ public final class IdePopupManager implements IdeEventQueue.EventDispatcher { && !ultimateParentForFocusedComponent.equals(ultimateParentForEventWindow)) { shouldCloseAllPopup = true; } + else if (focused instanceof Dialog && ((Dialog)focused).isModal()) { + shouldCloseAllPopup = true; + } } if (!shouldCloseAllPopup && isPopupWindow(sourceWindow) && sourceWindow.getParent() == ((WindowEvent)e).getOppositeWindow()) { shouldCloseAllPopup = true; From 03c39c23bc99912e452e21dda093d92f807ca1df Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 6 Apr 2017 18:35:34 +0200 Subject: [PATCH 009/111] create stub-based smart pointers even when AST is loaded --- .../SmartPsiElementPointersTest.java | 15 +++++++++++++++ .../SmartPsiElementPointerImpl.java | 18 +++++------------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java index 27c2bceb8e5b..b0ae8e2f8a4f 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/smartPointers/SmartPsiElementPointersTest.java @@ -24,6 +24,7 @@ import com.intellij.lang.FileASTNode; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.diagnostic.DefaultLogger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.EditorFactory; import com.intellij.openapi.editor.EditorModificationUtil; @@ -41,6 +42,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.psi.impl.source.PsiFileImpl; +import com.intellij.psi.impl.source.PsiJavaFileImpl; import com.intellij.psi.impl.source.tree.FileElement; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.stubs.StubElement; @@ -971,6 +973,7 @@ public class SmartPsiElementPointersTest extends CodeInsightTestCase { } public void testDoubleRemoveIsAnError() throws Exception { + DefaultLogger.disableStderrDumping(getTestRootDisposable()); SmartPointerEx pointer = createPointer(createFile("a.java", "class A {}")); getPointerManager().removePointer(pointer); try { @@ -982,4 +985,16 @@ public class SmartPsiElementPointersTest extends CodeInsightTestCase { } } + public void testStubSmartPointersAreCreatedEvenInAstPresence() throws Exception { + PsiJavaFileImpl file = (PsiJavaFileImpl)createFile("a.java", "class A {}"); + assertNotNull(file.getNode()); + SmartPointerEx pointer = createPointer(file.getClasses()[0]); + + PlatformTestUtil.tryGcSoftlyReachableObjects(); + assertNull(file.getTreeElement()); + + assertNotNull(pointer.getElement()); + assertNull(file.getTreeElement()); + } + } diff --git a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java index a46a47cdc50c..7510d47a1460 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPsiElementPointerImpl.java @@ -28,10 +28,7 @@ import com.intellij.psi.*; import com.intellij.psi.impl.FreeThreadedFileViewProvider; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.impl.source.PsiFileImpl; -import com.intellij.psi.impl.source.PsiFileWithStubSupport; import com.intellij.psi.impl.source.tree.ForeignLeafPsiElement; -import com.intellij.psi.stubs.IStubElementType; -import com.intellij.psi.stubs.StubTree; import com.intellij.psi.tree.IStubFileElementType; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; @@ -209,18 +206,13 @@ class SmartPsiElementPointerImpl implements SmartPointerEx @Nullable private static SmartPointerElementInfo createAnchorInfo(@NotNull PsiElement element, @NotNull PsiFile containingFile) { - if (element instanceof StubBasedPsiElement && containingFile instanceof PsiFileWithStubSupport) { - PsiFileWithStubSupport stubFile = (PsiFileWithStubSupport)containingFile; - StubTree stubTree = stubFile.getStubTree(); - if (stubTree != null) { - // use stubs when tree is not loaded + if (element instanceof StubBasedPsiElement && containingFile instanceof PsiFileImpl) { + IStubFileElementType stubType = ((PsiFileImpl)containingFile).getElementTypeForStubBuilder(); + if (stubType != null && stubType.shouldBuildStubFor(containingFile.getViewProvider().getVirtualFile())) { StubBasedPsiElement stubPsi = (StubBasedPsiElement)element; int stubId = PsiAnchor.calcStubIndex(stubPsi); - IStubElementType myStubElementType = stubPsi.getElementType(); - - IStubFileElementType elementTypeForStubBuilder = ((PsiFileImpl)containingFile).getElementTypeForStubBuilder(); - if (stubId != -1 && elementTypeForStubBuilder != null) { // TemplateDataElementType is not IStubFileElementType - return new AnchorElementInfo(element, stubFile, stubId, myStubElementType); + if (stubId != -1) { + return new AnchorElementInfo(element, (PsiFileImpl)containingFile, stubId, stubPsi.getElementType()); } } } From fa1f5c6228aceecd94fcba1fe1f3cedd32c486a6 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 6 Apr 2017 20:29:35 +0300 Subject: [PATCH 010/111] added documentation to the course --- .../edu/coursecreator/actions/CCCreateLesson.java | 6 ++---- .../actions/CCCreateStudyItemActionBase.java | 7 ++----- .../edu/coursecreator/actions/CCCreateTask.java | 6 ++---- .../handlers/CCLessonMoveHandlerDelegate.java | 4 +--- .../jetbrains/edu/learning/courseFormat/Course.java | 10 ++++++++-- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateLesson.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateLesson.java index 0436abb5132c..09e24daf3360 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateLesson.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateLesson.java @@ -15,8 +15,6 @@ import icons.EducationalCoreIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; - public class CCCreateLesson extends CCCreateStudyItemActionBase { public static final String TITLE = "Create New " + EduNames.LESSON_TITLED; @@ -82,8 +80,8 @@ public class CCCreateLesson extends CCCreateStudyItemActionBase { } @Override - protected List getSiblings(@NotNull Course course, @Nullable StudyItem parentItem) { - return course.getLessons(true); + protected void sortSiblings(@NotNull Course course, @Nullable StudyItem parentItem) { + course.sortLessons(); } @Override diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java index 4af27a9a372f..bad3979442b0 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java @@ -18,15 +18,12 @@ import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.coursecreator.ui.CCCreateStudyItemDialog; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; -import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.StudyItem; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.Collections; -import java.util.List; public abstract class CCCreateStudyItemActionBase extends DumbAwareAction { @@ -103,7 +100,7 @@ public abstract class CCCreateStudyItemActionBase extends DumbAwareAction { CCUtils.updateHigherElements(parentDir.getVirtualFile().getChildren(), getStudyOrderable(item), item.getIndex() - 1, getItemName(), 1); addItem(course, item); - Collections.sort(getSiblings(course, parentItem), EduUtils.INDEX_COMPARATOR); + sortSiblings(course, parentItem); return createItemDir(project, item, view, parentDir, course); } @@ -168,7 +165,7 @@ public abstract class CCCreateStudyItemActionBase extends DumbAwareAction { @NotNull final Project project, @NotNull final Course course); - protected abstract List getSiblings(@NotNull final Course course, @Nullable final StudyItem parentItem); + protected abstract void sortSiblings(@NotNull final Course course, @Nullable final StudyItem parentItem); protected abstract String getItemName(); diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java index 78e74feda957..f64e54b4a123 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java @@ -17,7 +17,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collections; -import java.util.List; public class CCCreateTask extends CCCreateStudyItemActionBase { public static final String TITLE = "Create New " + EduNames.TASK_TITLED; @@ -100,11 +99,10 @@ public class CCCreateTask extends CCCreateStudyItemActionBase { } @Override - protected List getSiblings(@NotNull Course course, @Nullable StudyItem parentItem) { + protected void sortSiblings(@NotNull Course course, @Nullable StudyItem parentItem) { if (parentItem instanceof Lesson) { - return ((Lesson)parentItem).getTaskList(); + Collections.sort(((Lesson)parentItem).getTaskList(), EduUtils.INDEX_COMPARATOR); } - return Collections.emptyList(); } @Override diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java index 3b163cd947ca..ebe4603afc9c 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/handlers/CCLessonMoveHandlerDelegate.java @@ -22,14 +22,12 @@ import com.jetbrains.edu.coursecreator.CCUtils; import com.jetbrains.edu.coursecreator.ui.CCMoveStudyItemDialog; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.core.EduNames; -import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.StudyItem; import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.util.Collections; public class CCLessonMoveHandlerDelegate extends MoveHandlerDelegate { @@ -109,7 +107,7 @@ public class CCLessonMoveHandlerDelegate extends MoveHandlerDelegate { newItemIndex - 1, EduNames.LESSON, 1); sourceLesson.setIndex(newItemIndex); - Collections.sort(course.getLessons(true), EduUtils.INDEX_COMPARATOR); + course.sortLessons(); ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/Course.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/Course.java index 9e4efbe46f33..d203b338f186 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/Course.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/Course.java @@ -44,13 +44,19 @@ public class Course { } } + /** + * exclude service lesson containing additional files for the course. Returns lessons copy. + */ public List getLessons() { return getLessons(false); } + /** + * returns service lesson as well. Meant to be used in project generation/serialization + */ public List getLessons(boolean withAdditional) { - return withAdditional ? lessons - : lessons.stream().filter(lesson -> !EduNames.PYCHARM_ADDITIONAL.equals(lesson.getName())).collect(Collectors.toList()); + return withAdditional ? lessons : lessons.stream().filter(lesson -> !EduNames.PYCHARM_ADDITIONAL.equals(lesson.getName())) + .collect(Collectors.toList()); } public void setLessons(List lessons) { From 608f974f257bc59b56c08983ac71208762ff405b Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 6 Apr 2017 19:50:59 +0200 Subject: [PATCH 011/111] trove5j license with reference to modified source code / change description --- license/trove4j_license.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 license/trove4j_license.txt diff --git a/license/trove4j_license.txt b/license/trove4j_license.txt new file mode 100644 index 000000000000..fd4ffe6a6564 --- /dev/null +++ b/license/trove4j_license.txt @@ -0,0 +1,21 @@ +The source code for GNU Trove is licensed under the Lesser GNU Public License (LGPL). + + Copyright (c) 2001, Eric D. Friedman All Rights Reserved. This library is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +Two classes (HashFunctions and PrimeFinder) included in Trove are licensed under the following terms: + + Copyright (c) 1999 CERN - European Organization for Nuclear Research. Permission to use, copy, modify, distribute and sell this software + and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and + that both that copyright notice and this permission notice appear in supporting documentation. CERN makes no representations about the + suitability of this software for any purpose. It is provided "as is" without expressed or implied warranty. + +The source code of modified GNU Trove library is available at + https://github.com/JetBrains/intellij-community/blob/master/lib/src/trove4j_src.jar (containing trove4j_changes.txt describing the changes) + or + https://github.com/JetBrains/trove4j (with trove4j_changes.txt describing the changes) From 3ab9fac128df510c3df5e1cffed9488fac602daa Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Thu, 6 Apr 2017 21:00:02 +0300 Subject: [PATCH 012/111] EDU-863 Task Description Not Showing --- .../learning/courseFormat/RemoteCourse.java | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/RemoteCourse.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/RemoteCourse.java index 01e764610e62..5ba3b62984c2 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/RemoteCourse.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/RemoteCourse.java @@ -2,9 +2,14 @@ package com.jetbrains.edu.learning.courseFormat; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; +import com.intellij.openapi.progress.EmptyProgressIndicator; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task.Backgroundable; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import com.jetbrains.edu.learning.stepic.EduStepicConnector; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Date; @@ -18,6 +23,7 @@ public class RemoteCourse extends Course { List instructors = new ArrayList<>(); @Expose private int id; @Expose @SerializedName("update_date") private Date myUpdateDate; + private Boolean isUpToDate = true; @Expose private boolean isAdaptive = false; @SerializedName("is_public") boolean isPublic; @@ -45,14 +51,24 @@ public class RemoteCourse extends Course { public boolean isUpToDate() { if (id == 0) return true; if (!EduNames.STUDY.equals(courseMode)) return true; - final Date date = EduStepicConnector.getCourseUpdateDate(id); - if (date == null) return true; - if (myUpdateDate == null) return true; - if (date.after(myUpdateDate)) return false; - for (Lesson lesson : lessons) { - if (!lesson.isUpToDate()) return false; - } - return true; + + ProgressManager.getInstance().runProcessWithProgressAsynchronously(new Backgroundable(null, "Updating Course") { + @Override + public void run(@NotNull ProgressIndicator indicator) { + final Date date = EduStepicConnector.getCourseUpdateDate(id); + if (date == null) return; + if (date.after(myUpdateDate)) { + isUpToDate = false; + } + for (Lesson lesson : lessons) { + if (!lesson.isUpToDate()) { + isUpToDate = false; + } + } + } + }, new EmptyProgressIndicator()); + + return isUpToDate; } public void setUpdated() { From 00f7d735eece672390c8595c0ed0efedd8ecb690 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Thu, 6 Apr 2017 19:29:48 +0300 Subject: [PATCH 013/111] Delete outdated scripts --- build/conf/jreVersions.properties | 3 - build/scripts/download_jre.gant | 90 -------- build/scripts/download_kotlin.gant | 328 ----------------------------- 3 files changed, 421 deletions(-) delete mode 100644 build/conf/jreVersions.properties delete mode 100644 build/scripts/download_jre.gant delete mode 100644 build/scripts/download_kotlin.gant diff --git a/build/conf/jreVersions.properties b/build/conf/jreVersions.properties deleted file mode 100644 index 2b58cecdd81e..000000000000 --- a/build/conf/jreVersions.properties +++ /dev/null @@ -1,3 +0,0 @@ -trunk=481 -eap=481 -release=408 \ No newline at end of file diff --git a/build/scripts/download_jre.gant b/build/scripts/download_jre.gant deleted file mode 100644 index 3437c08b9d81..000000000000 --- a/build/scripts/download_jre.gant +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2000-2017 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. - */ - -import com.intellij.openapi.util.SystemInfo - -import java.util.regex.Pattern - -target('default': 'Downloads custom JRE build from Teamcity server') { - def platform = SystemInfo.isMac ? "mac" : SystemInfo.isWindows ? "win" : SystemInfo.isLinux ? "linux" : "" - if (platform == "") { - echo "Unsupported platform, JRE download skipped" - return - } - if (jreArchitecture == "disable") { - echo "JRE update disabled" - return - } - if (!(jreArchitecture == "64" || jreArchitecture == "32" && platform == "win")) { - echo "Acceptable architecture (32 or 64 bit) is not defined, JRE download skipped" - return - } - - def majorBuildNumber = ideBuildNumber.split(/\./)[0] - def buildConfiguration = jreBuildTypeId.replaceAll(/#build#/, majorBuildNumber) - - String buildId, buildNumber - try { - buildId = new URL("$jreTeamcityUrl/buildTypes/id:$buildConfiguration/builds/tags:$jreBuildTag/id").text - buildNumber = new URL("$jreTeamcityUrl/builds/id:$buildId/number").text - } - catch (IOException e) { - echo "Build server connection failed: ${e.message}, JRE download skipped" - return - } - - java(jvm: SystemInfo.isMac ? "$workIdeaHome/jdk/Contents/Home/jre/bin/java" : "$workIdeaHome/jre/jre/bin/java", - fork: "true", classname: "dummy", outputproperty: "jvmVersionOutput") { - jvmarg(value: "-version") - } - try { - if (jvmVersionOutput =~ /\(build .*release-${Pattern.quote(buildNumber.replace(".", "-b"))}\)/ && - jvmVersionOutput =~ (jreArchitecture == "64" ? /OpenJDK 64-Bit Server VM/ : /OpenJDK Server VM/)) { - echo "Latest version of custom JRE is installed, no update is required" - return - } - } - catch (MissingPropertyException ignored) { - echo "Could'nt determine existing JRE version" - } - def files = new XmlSlurper().parse("$jreTeamcityUrl/builds/id:$buildId/artifacts/children/$platform") - def artifact = files.children().collect { it.@name.text() }.find { - it.startsWith(jreArtifactPrefix) && it.endsWith(jreArchitecture == "64" ? "_x64.tar.gz" : "_x86.tar.gz") && !it.contains("debug") - } - get src: "$jreTeamcityUrl/builds/id:$buildId/artifacts/content/$platform/$artifact", dest: deployDir - if (SystemInfo.isWindows) { - mkdir dir: "$deployDir/jre" - untar src: "$deployDir/$artifact", dest: "$deployDir/jre", compression: "gzip" - } - else if (SystemInfo.isMac) { - // untar task doesn't support symlinks, so we need to use native tar executable - exec(executable: "tar", dir: "$deployDir") { - arg(value: "-xf") - arg(value: "$artifact") - } - } - else if (SystemInfo.isLinux) { - mkdir dir: "$deployDir/jre" - // untar task doesn't support symlinks, so we need to use native tar executable - exec(executable: "tar", dir: "$deployDir") { - arg(value: "-xf") - arg(value: "$artifact") - arg(value: "--directory") - arg(value: "jre") - } - } - delete file: "$deployDir/$artifact" -} \ No newline at end of file diff --git a/build/scripts/download_kotlin.gant b/build/scripts/download_kotlin.gant deleted file mode 100644 index c6f2a57364f5..000000000000 --- a/build/scripts/download_kotlin.gant +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright 2000-2017 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. - */ - -import com.intellij.openapi.util.text.StringUtil -import com.intellij.util.text.VersionComparatorUtil -import groovyjarjarasm.asm.AnnotationVisitor -import groovyjarjarasm.asm.ClassReader -import groovyjarjarasm.asm.ClassVisitor -import groovyjarjarasm.asm.Opcodes - -import java.util.jar.JarFile - -import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome - -includeTargets << new File("${guessHome(this)}/build/scripts/utils.gant") - -String kotlinBuildConfigurationOnPublicTeamCity = "Kotlin_110_CompilerAndPlugin_NoTests" - -target('default': 'Ensures that build/kotlinc directory contains JARs from Kotlin plugin compatible with current IDEA sources. These JARs are used by build scripts.') { - def communityHome = guessHome(this) - def classVersionOfCompiledClasses = readKotlinClassVersionOfCompiledClasses() - def reasonToUpdate = getReasonToUpdate(communityHome, new File(communityHome, "build/kotlinc/plugin/Kotlin"), classVersionOfCompiledClasses) - if (reasonToUpdate == null) { - if (isDefined("workIdeaHome")) { - def workKotlinVersionFile = new File(workIdeaHome, "plugins/Kotlin/kotlinc/build.txt") - if (workKotlinVersionFile.exists()) { - try { - def currentKotlinVersionFile = new File(communityHome, "build/kotlinc/build.txt") - if (VersionComparatorUtil.compare(currentKotlinVersionFile.text, workKotlinVersionFile.text) < 0) { - reasonToUpdate = "a newer version is installed in $workIdeaHome" - } - } - catch (IOException e) { - reasonToUpdate = "cannot read Kotlin version: $e" - } - } - } - - if (reasonToUpdate == null) { - projectBuilder.info("Compatible Kotlin plugin already installed, no update is required") - return - } - } - - projectBuilder.info("Kotlin plugin will be updated: $reasonToUpdate") - - if (isDefined("workIdeaHome")) { - if (updatePluginFromWorkIdeaInstallation(communityHome, workIdeaHome, classVersionOfCompiledClasses)) { - return - } - } - - if (isDefined("kotlin.teamcity.host")) { - if (downloadAndExtract(new TeamCityBuildLocator(p("kotlin.teamcity.host"), p("kotlin.build.type.id"), p("kotlin.build.selector")), - communityHome, classVersionOfCompiledClasses)) { - return - } - } - if (!downloadAndExtract(new TeamCityBuildLocator("https://teamcity.jetbrains.com", kotlinBuildConfigurationOnPublicTeamCity, "status:SUCCESS"), - communityHome, classVersionOfCompiledClasses)) { - projectBuilder.error("Failed to install Kotlin plugin") - } -} - -private boolean updatePluginFromWorkIdeaInstallation(String communityHome, String workIdeaHome, String classVersionOfCompiledClasses) { - def kotlinPluginFromWorkIdea = new File(workIdeaHome, "plugins/Kotlin") - if (!kotlinPluginFromWorkIdea.exists()) { - projectBuilder.info("Cannot use Kotlin from $workIdeaHome: the plugin directory doesn't exist") - return false - } - - def reasonToUpdate = getReasonToUpdate(communityHome, kotlinPluginFromWorkIdea, classVersionOfCompiledClasses) - if (reasonToUpdate != null) { - projectBuilder.info("Cannot use Kotlin from $workIdeaHome: $reasonToUpdate") - return false - } - - ant.delete(dir: "$communityHome/build/kotlinc") - ant.copy(todir: "$communityHome/build/kotlinc/plugin/Kotlin") { - ant.fileset(dir: kotlinPluginFromWorkIdea) - } - ant.copy(todir: "$communityHome/build/kotlinc") { - ant.fileset(dir: "$kotlinPluginFromWorkIdea/kotlinc") - } - ant.copy(todir: "$communityHome/build/kotlinc/jps") { - ant.fileset(dir: "$kotlinPluginFromWorkIdea/lib/jps") - } - projectBuilder.info("Kotlin plugin updated from $workIdeaHome installation") - return true -} - -private String getReasonToUpdate(String communityHome, File kotlinPluginHome, String classVersionOfCompiledClasses) { - def kotlincHome = new File(kotlinPluginHome, "kotlinc") - def buildTxt = new File(kotlincHome, "build.txt") - if (!buildTxt.exists()) { - return "Kotlin binaries aren't found at $kotlincHome" - } - - if (classVersionOfCompiledClasses != null) { - def currentKotlinClassVersion = detectKotlinClassVersionForKotlinDist(kotlincHome) - if (currentKotlinClassVersion == null) { - projectBuilder.info("Cannot detect Kotlin class file version for $kotlincHome, class file versions compatibility won't be checked") - } - else if (VersionComparatorUtil.compare(currentKotlinClassVersion, classVersionOfCompiledClasses) < 0) { - return "Kotlin compiler produces class-files of version $currentKotlinClassVersion, but IDEA classes have version $classVersionOfCompiledClasses" - } - } - - String currentKotlinVersion - try { - currentKotlinVersion = buildTxt.text - } - catch (IOException e) { - return "cannot read Kotlin version from $buildTxt.absolutePath: $e" - } - - def externalDependenciesXml = new File(communityHome, ".idea/externalDependencies.xml") - if (!externalDependenciesXml.exists()) { - return "cannot read required Kotlin version from $externalDependenciesXml.absolutePath: the file doesn't exist" - } - - def root = new XmlParser().parse(externalDependenciesXml) - def pluginTag = root.component?.find { it.@name == "ExternalDependencies" }?.plugin?.find { it.@id == "org.jetbrains.kotlin" } - if (pluginTag == null) return "cannot find Kotlin plugin in $externalDependenciesXml.absolutePath" - - String minVersion = pluginTag['@min-version'] - if (minVersion == null) return "minimum required version for Kotlin plugin isn't specified in $externalDependenciesXml.absolutePath" - String maxVersion = pluginTag['@max-version'] - if (maxVersion == null) return "maximum required version for Kotlin plugin isn't specified in $externalDependenciesXml.absolutePath" - - if (VersionComparatorUtil.compare(currentKotlinVersion, minVersion) < 0) { - return "Kotlin version is $currentKotlinVersion, but at least $minVersion is required"; - } - if (VersionComparatorUtil.compare(currentKotlinVersion, maxVersion) > 0) { - return "Kotlin version is $currentKotlinVersion, but at most $maxVersion is required"; - } - - String ideVersion - def ideVersionFile = new File(communityHome, "build.txt") - try { - ideVersion = ideVersionFile.text - } - catch (IOException e) { - return "cannot read IDE version from $ideVersionFile: $e" - } - def pluginJar = new File(kotlinPluginHome, "lib/kotlin-plugin.jar") - String pluginUntilBuild - try { - def jarFile = new JarFile(pluginJar) - try { - def pluginXmlEntry = jarFile.getEntry("META-INF/plugin.xml") - if (pluginXmlEntry == null) { - return "cannot check Kotlin plugin compatibility (META-INF/plugin.xml not found in $pluginJar)" - } - def pluginXml = new XmlParser().parse(jarFile.getInputStream(pluginXmlEntry)) - pluginUntilBuild = pluginXml."idea-version"?.first()?."@until-build" - if (pluginUntilBuild != null) { - String ideVersionBaseLine = StringUtil.substringBefore(ideVersion, ".") - String pluginUntilBuildBaseLine = StringUtil.substringBefore(pluginUntilBuild, ".") - if (ideVersionBaseLine > pluginUntilBuildBaseLine) { - return "Kotlin plugin isn't compatible with $ideVersion (its 'until-build' is $pluginUntilBuild)" - } - } - } - finally { - jarFile.close() - } - } - catch (Exception e) { - return "cannot check Kotlin plugin compatibility: $e" - } - return null -} - -private String detectKotlinClassVersionForKotlinDist(File kotlincHome) { - def kotlinRuntimeFile = new File(kotlincHome, "lib/kotlin-runtime.jar") - def kotlinRuntimeJar = new JarFile(kotlinRuntimeFile) - try { - try { - def unitClassPath = "kotlin/Unit.class" - def entry = kotlinRuntimeJar.getJarEntry(unitClassPath) - if (entry == null) { - projectBuilder.warning("Cannot find $unitClassPath in $kotlinRuntimeJar") - return null - } - return readKotlinClassFileVersion(kotlinRuntimeJar.getInputStream(entry)) - } - finally { - kotlinRuntimeJar.close() - } - } - catch (IOException e) { - projectBuilder.warning("Cannot detect Kotlin class file version for Kotlin distribution: $e") - return null - } -} - - -private String readKotlinClassVersionOfCompiledClasses() { - if (!isDefined("modulesOutput")) return null - - def kotlinClassFile = new File("$modulesOutput/production/execution-impl/com/intellij/execution/ui/DefaultJreSelector.class") - if (!kotlinClassFile.exists()) { - projectBuilder.warning("Cannot detect Kotlin class file version of IDEA classes: $kotlinClassFile doesn't exist") - return null - } - - try { - return kotlinClassFile.withInputStream { readKotlinClassFileVersion(it) } - } - catch (IOException e) { - projectBuilder.warning("Cannot detect Kotlin class file version of IDEA classes: $e") - return null - } -} - -private static String readKotlinClassFileVersion(InputStream classFileStream) { - def reader = new ClassReader(classFileStream) - String kotlinBytecodeVersion = null - String kotlinMetaDataVersion = null - reader.accept(new ClassVisitor(Opcodes.ASM5) { - AnnotationVisitor visitAnnotation(String annotationName, boolean b) { - if (annotationName == "Lkotlin/jvm/internal/KotlinClass;") { - return new AnnotationVisitor(Opcodes.ASM5) { - void visit(String name, Object value) { - if (name == "version") { - kotlinBytecodeVersion = (value as Integer[]).join(".") - } - } - } - } - else if (annotationName == "Lkotlin/Metadata;") { - return new AnnotationVisitor(Opcodes.ASM5) { - void visit(String name, Object value) { - if (name == "mv") { - //strip patch number of metadata version because changes in patch updates are forward and backward compatible - kotlinMetaDataVersion = (value as Integer[]).toList().dropRight(1).join(".") - } - else if (name == "bv") { - kotlinBytecodeVersion = (value as Integer[]).join(".") - } - } - } - } - return null - } - }, 0) - if (kotlinBytecodeVersion != null && kotlinMetaDataVersion != null) { - kotlinBytecodeVersion = kotlinBytecodeVersion + "." + kotlinMetaDataVersion - } - return kotlinBytecodeVersion -} - -private boolean downloadAndExtract(TeamCityBuildLocator buildLocator, String communityHome, String classVersionOfCompiledClasses) { - String buildNumber; - try { - buildNumber = new URL(buildLocator.buildNumberUrl).text - } - catch (Exception e) { - projectBuilder.info("Cannot get Kotlin build number from $buildLocator.buildNumberUrl: $e") - return false - } - - - def pluginZip = new File(communityHome, "build/kotlin-plugin-${buildNumber}.zip") - def pluginZipPath = pluginZip.absolutePath - if (!pluginZip.exists()) { - ant.delete(dir: "$communityHome/build", includes: "kotlin-plugin-*.zip") - projectBuilder.info("Downloading Kotlin build $buildNumber") - ant.get(src: buildLocator.getDownloadUrl(buildNumber), dest: pluginZipPath) - } - else { - projectBuilder.info("Extracting Kotlin build $buildNumber") - } - - def kotlincDir = "$communityHome/build/kotlinc" - ant.delete(dir: kotlincDir) - ant.unzip(src: pluginZipPath, dest: "$kotlincDir/plugin") - ant.unzip(src: pluginZipPath, dest: "$kotlincDir") { - ant.patternset(includes: "Kotlin/kotlinc/**") - ant.globmapper(from: "Kotlin/kotlinc/*", to: "*") - } - ant.unzip(src: pluginZipPath, dest: "$kotlincDir/jps") { - ant.patternset(includes: "Kotlin/lib/jps/**") - ant.globmapper(from: "Kotlin/lib/jps/*", to: "*") - } - def reasonToUpdate = getReasonToUpdate(communityHome, new File(kotlincDir, "plugin/Kotlin"), classVersionOfCompiledClasses) - if (reasonToUpdate != null) { - projectBuilder.warning("Cannot use the downloaded Kotlin plugin: $reasonToUpdate") - } - return true -} - -class TeamCityBuildLocator { - String host; - String buildTypeId; - String buildSelector; - - TeamCityBuildLocator(String host, String buildTypeId, String buildSelector) { - this.host = host - this.buildTypeId = buildTypeId - this.buildSelector = buildSelector - } - - String getBuildNumberUrl() { - return "$host/guestAuth/app/rest/buildTypes/id:$buildTypeId/builds/$buildSelector,count:1/number" - } - - String getDownloadUrl(String buildNumber) { - String encodedBuildNumber = URLEncoder.encode(buildNumber, "UTF-8") - int index = encodedBuildNumber.lastIndexOf('-') - String releaseBuildNumber = encodedBuildNumber.substring(0, index) - return "$host/guestAuth/repository/download/$buildTypeId/$encodedBuildNumber/kotlin-plugin-$releaseBuildNumber-IJ2017.1-1.zip" - } -} From 6073068ba0ee7d531795e2af6f0faf27ad6c9988 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Thu, 6 Apr 2017 21:21:18 +0300 Subject: [PATCH 014/111] External dependencies: avoid cleaning jbre archives on each run --- .../build/impl/BuildContextImpl.groovy | 2 +- .../build/impl/BundledJreManager.groovy | 38 +++++++++++-------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy index 1fa1d7b2004a..635c44e563e3 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy @@ -78,7 +78,7 @@ class BuildContextImpl extends BuildContext { private static void setupDependencies(BuildMessages messages, String communityHome) { messages.info("Setting up installer dependencies") - if (!BuildUtils.gradle(new File(communityHome, 'build/dependencies/'), 'cleanSetupJbre', 'setupDependencies')) { + if (!BuildUtils.gradle(new File(communityHome, 'build/dependencies/'), 'setupDependencies')) { messages.error("Cannot setup installer dependencies") } } diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy index 8cf0694cd348..db6c5120502c 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy @@ -118,22 +118,16 @@ class BundledJreManager { } private File findJreArchive(String osName, JvmArchitecture arch = JvmArchitecture.x64, JreVendor vendor = JreVendor.JetBrains) { - def jreDir = new File(buildContext.paths.communityHome, "build/dependencies/build/jbre") - String suffix = "_$osName${arch == JvmArchitecture.x32 ? '_x86' : '_x64'}.tar.gz" - String prefix = buildContext.productProperties.toolsJarRequired ? vendor.jreWithToolsJarNamePrefix : vendor.jreNamePrefix - Collection jreFiles = jreDir.listFiles()?.findAll { it.file && it.name.startsWith(prefix) && it.name.endsWith(suffix) } ?: [] as List - String errorMessage; - if (jreFiles.size() > 1) { - errorMessage = "Cannot extract $osName JRE: several matching files are found ($jreFiles)" - } - else if (jreFiles.isEmpty()) { - errorMessage = "Cannot extract $osName JRE: no '${prefix}...${suffix}' files found in $jreDir" - } - else { - errorMessage = null - } + def dependenciesDir = new File(buildContext.paths.communityHome, 'build/dependencies') + def jreDir = new File(dependenciesDir, 'build/jbre') + def jreVersion = getExpectedJreVersion(dependenciesDir) - if (errorMessage != null) { + String suffix = "${jreVersion}_$osName${arch == JvmArchitecture.x32 ? '_x86' : '_x64'}.tar.gz" + String prefix = buildContext.productProperties.toolsJarRequired ? vendor.jreWithToolsJarNamePrefix : vendor.jreNamePrefix + def jreArchive = new File(jreDir, "$prefix$suffix") + + if (!jreArchive.file || !jreArchive.exists()) { + def errorMessage = "Cannot extract $osName JRE: file $jreArchive is not found (${jreDir.listFiles()})" if (buildContext.options.isInDevelopmentMode) { buildContext.messages.warning(errorMessage) } @@ -142,7 +136,19 @@ class BundledJreManager { } return null } - return jreFiles.first() + return jreArchive + } + + private static String getExpectedJreVersion(File dependenciesDir) { + def properties = new Properties() + def stream = new File(dependenciesDir, 'gradle.properties').newInputStream() + try { + properties.load(stream) + return properties.get("jdkBuild", "") + } + finally { + stream.close() + } } private enum JreVendor { From b30506e0d0103e030eb50dd00100738c26b91490 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Thu, 6 Apr 2017 20:43:34 +0200 Subject: [PATCH 015/111] do not use leading slash when requesting resource: it is non STD classloader behavior to retrieve resources with such path --- .../com/intellij/codeInspection/ex/InspectionToolWrapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/analysis-api/src/com/intellij/codeInspection/ex/InspectionToolWrapper.java b/platform/analysis-api/src/com/intellij/codeInspection/ex/InspectionToolWrapper.java index 5aec1c33928d..46bd56e55668 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/ex/InspectionToolWrapper.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/ex/InspectionToolWrapper.java @@ -188,13 +188,13 @@ public abstract class InspectionToolWrapper Date: Thu, 6 Apr 2017 19:34:50 +0200 Subject: [PATCH 016/111] IG: reusable & simpler UI code --- .../ui/MultipleCheckboxOptionsPanel.java | 26 +++++-- ...lOnLocalVariableOrParameterInspection.java | 75 ++++--------------- 2 files changed, 32 insertions(+), 69 deletions(-) diff --git a/platform/analysis-api/src/com/intellij/codeInspection/ui/MultipleCheckboxOptionsPanel.java b/platform/analysis-api/src/com/intellij/codeInspection/ui/MultipleCheckboxOptionsPanel.java index ca95906a316f..99d84b74ebcd 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/ui/MultipleCheckboxOptionsPanel.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/ui/MultipleCheckboxOptionsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -16,9 +16,11 @@ package com.intellij.codeInspection.ui; import com.intellij.codeInspection.InspectionProfileEntry; +import com.intellij.util.ui.JBInsets; import org.jetbrains.annotations.NonNls; import javax.swing.*; +import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.*; @@ -40,10 +42,25 @@ public class MultipleCheckboxOptionsPanel extends JPanel { } public void addCheckbox(String label, @NonNls String property) { + addCheckboxEx(label, property); + } + + public JCheckBox addCheckboxEx(String label, @NonNls String property) { final boolean selected = myOptionAccessor.getOption(property); final JCheckBox checkBox = new JCheckBox(label, selected); configureCheckbox(myOptionAccessor, property, checkBox); addComponent(checkBox); + return checkBox; + } + + public JCheckBox addDependentCheckBox(String label, @NonNls String property, JCheckBox controller) { + final JCheckBox checkBox = addCheckboxEx(label, property); + checkBox.setBorder(new EmptyBorder(new JBInsets(0, 30, 0, 0))); + controller.addChangeListener(e -> { + checkBox.setEnabled(controller.isEnabled() && controller.isSelected()); + }); + checkBox.setEnabled(controller.isEnabled() && controller.isSelected()); + return checkBox; } public void addComponent(JComponent component) { @@ -68,12 +85,6 @@ public class MultipleCheckboxOptionsPanel extends JPanel { model.addChangeListener(changeListener); } - public static void initAndConfigureCheckbox(InspectionProfileEntry owner, String property, JCheckBox checkBox) { - OptionAccessor optionAccessor = new OptionAccessor.Default(owner); - checkBox.setSelected(optionAccessor.getOption(property)); - configureCheckbox(optionAccessor, property, checkBox); - } - private static class CheckboxChangeListener implements ChangeListener { private final OptionAccessor myAccessor; private final String property; @@ -89,6 +100,5 @@ public class MultipleCheckboxOptionsPanel extends JPanel { public void stateChanged(ChangeEvent e) { myAccessor.setOption(property, model.isSelected()); } - } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryFinalOnLocalVariableOrParameterInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryFinalOnLocalVariableOrParameterInspection.java index 51652fbb4bf8..ea23c74b7dc6 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryFinalOnLocalVariableOrParameterInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryFinalOnLocalVariableOrParameterInspection.java @@ -16,10 +16,10 @@ package com.siyeh.ig.style; import com.intellij.codeInspection.CleanupLocalInspectionTool; +import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; @@ -29,9 +29,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; + +import static com.siyeh.InspectionGadgetsBundle.message; public class UnnecessaryFinalOnLocalVariableOrParameterInspection extends BaseInspection implements CleanupLocalInspectionTool { @@ -47,7 +46,7 @@ public class UnnecessaryFinalOnLocalVariableOrParameterInspection extends BaseIn @Override @NotNull public String getDisplayName() { - return InspectionGadgetsBundle.message("unnecessary.final.on.local.variable.or.parameter.display.name"); + return message("unnecessary.final.on.local.variable.or.parameter.display.name"); } @Override @@ -56,73 +55,27 @@ public class UnnecessaryFinalOnLocalVariableOrParameterInspection extends BaseIn final PsiVariable variable = (PsiVariable)infos[0]; final String variableName = variable.getName(); if (variable instanceof PsiParameter) { - return InspectionGadgetsBundle.message("unnecessary.final.on.parameter.problem.descriptor", variableName); + return message("unnecessary.final.on.parameter.problem.descriptor", variableName); } else { - return InspectionGadgetsBundle.message("unnecessary.final.on.local.variable.problem.descriptor", variableName); + return message("unnecessary.final.on.local.variable.problem.descriptor", variableName); } } @Override @Nullable public JComponent createOptionsPanel() { - final JPanel panel = new JPanel(new GridBagLayout()); - final JCheckBox abstractOnlyCheckBox = - new JCheckBox(InspectionGadgetsBundle.message("unnecessary.final.on.parameter.only.interface.option"), onlyWarnOnAbstractMethods) { - @Override - public void setEnabled(boolean b) { - // hack to display correctly on initial opening of - // inspection settings (otherwise it is always enabled) - if (b) { - super.setEnabled(reportParameters); - } - else { - super.setEnabled(false); - } - } - }; - abstractOnlyCheckBox.setEnabled(true); - abstractOnlyCheckBox.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - onlyWarnOnAbstractMethods = abstractOnlyCheckBox.isSelected(); - } - }); - final JCheckBox reportLocalVariablesCheckBox = - new JCheckBox(InspectionGadgetsBundle.message("unnecessary.final.report.local.variables.option"), reportLocalVariables); - final JCheckBox reportParametersCheckBox = - new JCheckBox(InspectionGadgetsBundle.message("unnecessary.final.report.parameters.option"), reportParameters); + final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this); + final JCheckBox box1 = panel.addCheckboxEx(message("unnecessary.final.report.local.variables.option"), "reportLocalVariables"); + final JCheckBox box2 = panel.addCheckboxEx(message("unnecessary.final.report.parameters.option"), "reportParameters"); + panel.addDependentCheckBox(message("unnecessary.final.on.parameter.only.interface.option"), "onlyWarnOnAbstractMethods", box2); - reportLocalVariablesCheckBox.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - reportLocalVariables = reportLocalVariablesCheckBox.isSelected(); - if (!reportLocalVariables) { - reportParametersCheckBox.setSelected(true); - } - } + box1.addChangeListener(e -> { + if (!box1.isSelected()) box2.setSelected(true); }); - reportParametersCheckBox.addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - reportParameters = reportParametersCheckBox.isSelected(); - if (!reportParameters) { - reportLocalVariablesCheckBox.setSelected(true); - } - abstractOnlyCheckBox.setEnabled(reportParameters); - } + box2.addChangeListener(e -> { + if (!box2.isSelected()) box1.setSelected(true); }); - final GridBagConstraints constraints = new GridBagConstraints(); - constraints.anchor = GridBagConstraints.NORTHWEST; - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - panel.add(reportLocalVariablesCheckBox, constraints); - constraints.gridy = 1; - panel.add(reportParametersCheckBox, constraints); - constraints.insets.left = 20; - constraints.gridy = 2; - constraints.weighty = 1.0; - panel.add(abstractOnlyCheckBox, constraints); return panel; } From 8a39fee95945a990d2f02aa4fddee2591a389c13 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 6 Apr 2017 20:37:31 +0200 Subject: [PATCH 017/111] IG: add option to ignore all primitive arrays (IDEA-170812) --- .../siyeh/InspectionGadgetsBundle.properties | 1 + ...hodCanBeVariableArityMethodInspection.java | 28 +++++++++++-------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties index 8eb966316faa..ea03a59930c2 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1855,6 +1855,7 @@ arrays.hash.code.quickfix=Replace with 'Arrays.hashCode()' method.can.be.variable.arity.method.display.name=Method can be varargs method method.can.be.variable.arity.method.problem.descriptor=#ref() can be converted to varargs method #loc method.can.be.variable.arity.method.ignore.byte.short.option=Ignore parameters with type byte[] or short[] +method.can.be.variable.arity.method.ignore.all.primitive.arrays.option=Ignore all primitive array types method.can.be.variable.arity.method.ignore.multiple.arrays.option=Ignore methods with multiple array parameters method.can.be.variable.arity.method.ignore.multidimensional.arrays.option=Ignore multidimensional array parameters convert.to.variable.arity.method.quickfix=Convert to varargs method diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/MethodCanBeVariableArityMethodInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/MethodCanBeVariableArityMethodInspection.java index 34bbdb67b0b8..e51ec9edbb60 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/MethodCanBeVariableArityMethodInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/MethodCanBeVariableArityMethodInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2016 Bas Leijdekkers + * Copyright 2011-2017 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; -import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; @@ -31,11 +30,15 @@ import org.jetbrains.annotations.NotNull; import javax.swing.*; +import static com.siyeh.InspectionGadgetsBundle.message; + public class MethodCanBeVariableArityMethodInspection extends BaseInspection { @SuppressWarnings({"PublicField"}) public boolean ignoreByteAndShortArrayParameters = false; + public boolean ignoreAllPrimitiveArrayParameters = false; + @SuppressWarnings("PublicField") public boolean ignoreOverridingMethods = false; @@ -52,26 +55,24 @@ public class MethodCanBeVariableArityMethodInspection extends BaseInspection { @NotNull @Override public String getDisplayName() { - return InspectionGadgetsBundle.message("method.can.be.variable.arity.method.display.name"); + return message("method.can.be.variable.arity.method.display.name"); } @NotNull @Override protected String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message("method.can.be.variable.arity.method.problem.descriptor"); + return message("method.can.be.variable.arity.method.problem.descriptor"); } @Override public JComponent createOptionsPanel() { final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this); - panel.addCheckbox(InspectionGadgetsBundle.message("method.can.be.variable.arity.method.ignore.byte.short.option"), - "ignoreByteAndShortArrayParameters"); - panel.addCheckbox(InspectionGadgetsBundle.message("ignore.methods.overriding.super.method"), "ignoreOverridingMethods"); - panel.addCheckbox(InspectionGadgetsBundle.message("only.report.public.methods.option"), "onlyReportPublicMethods"); - panel.addCheckbox(InspectionGadgetsBundle.message("method.can.be.variable.arity.method.ignore.multiple.arrays.option"), - "ignoreMultipleArrayParameters"); - panel.addCheckbox(InspectionGadgetsBundle.message("method.can.be.variable.arity.method.ignore.multidimensional.arrays.option"), - "ignoreMultiDimensionalArrayParameters"); + final JCheckBox box = panel.addCheckboxEx(message("method.can.be.variable.arity.method.ignore.byte.short.option"), "ignoreByteAndShortArrayParameters"); + panel.addDependentCheckBox(message("method.can.be.variable.arity.method.ignore.all.primitive.arrays.option"), "ignoreAllPrimitiveArrayParameters", box); + panel.addCheckbox(message("ignore.methods.overriding.super.method"), "ignoreOverridingMethods"); + panel.addCheckbox(message("only.report.public.methods.option"), "onlyReportPublicMethods"); + panel.addCheckbox(message("method.can.be.variable.arity.method.ignore.multiple.arrays.option"), "ignoreMultipleArrayParameters"); + panel.addCheckbox(message("method.can.be.variable.arity.method.ignore.multidimensional.arrays.option"), "ignoreMultiDimensionalArrayParameters"); return panel; } @@ -121,6 +122,9 @@ public class MethodCanBeVariableArityMethodInspection extends BaseInspection { if (PsiType.BYTE.equals(componentType) || PsiType.SHORT.equals(componentType)) { return; } + if (ignoreAllPrimitiveArrayParameters && componentType instanceof PsiPrimitiveType) { + return; + } } if (LibraryUtil.isOverrideOfLibraryMethod(method)) { return; From ce598ae801c3a2c880cd816af75493ff77fd1f13 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 6 Apr 2017 20:58:50 +0200 Subject: [PATCH 018/111] [ui] distinguishes IDE and plugin updates (IDEA-169473) --- .../updateSettings/impl/CheckForUpdateAction.java | 9 +++++++-- .../openapi/updateSettings/impl/NoUpdatesDialog.java | 10 ++++++++-- .../openapi/updateSettings/impl/UpdateChecker.kt | 4 +--- .../openapi/updateSettings/impl/UpdateSettings.java | 10 ++++++++-- .../src/messages/ActionsBundle.properties | 3 ++- .../src/messages/IdeBundle.properties | 8 +++++--- 6 files changed, 31 insertions(+), 13 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java index fd60e6407198..f80d4b47c7fc 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -15,6 +15,7 @@ */ package com.intellij.openapi.updateSettings.impl; +import com.intellij.idea.ActionsBundle; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -33,10 +34,14 @@ public class CheckForUpdateAction extends AnAction implements DumbAware { else { e.getPresentation().setVisible(!SystemInfo.isMacSystemMenu || !ActionPlaces.MAIN_MENU.equals(place)); } + + if (!UpdateSettings.getInstance().isPlatformUpdateEnabled()) { + e.getPresentation().setDescription(ActionsBundle.message("action.CheckForUpdate.description.plugins")); + } } @Override public void actionPerformed(@NotNull AnActionEvent e) { UpdateChecker.updateAndShowResult(e.getProject(), null); } -} +} \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesDialog.java index 90c7b315267f..fc1d0c729152 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesDialog.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -53,7 +53,13 @@ class NoUpdatesDialog extends AbstractUpdateDialog { private JEditorPane myMessageArea; public NoUpdatesPanel() { - myNothingToUpdateLabel.setText(IdeBundle.message("updates.no.updates.message", ApplicationInfo.getInstance().getVersionName())); + if (UpdateSettings.getInstance().isPlatformUpdateEnabled()) { + String app = ApplicationInfo.getInstance().getVersionName(); + myNothingToUpdateLabel.setText(IdeBundle.message("updates.no.updates.message", app)); + } + else { + myNothingToUpdateLabel.setText(IdeBundle.message("updates.no.updates.plugins.message")); + } configureMessageArea(myMessageArea); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.kt b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.kt index 5f2d4b8ff499..093132648c48 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.kt +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.kt @@ -42,7 +42,6 @@ import com.intellij.openapi.util.BuildNumber import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.text.StringUtil -import com.intellij.util.SystemProperties import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.MultiMap import com.intellij.util.io.HttpRequests @@ -69,7 +68,6 @@ object UpdateChecker { val NOTIFICATIONS = NotificationGroup(IdeBundle.message("update.notifications.title"), NotificationDisplayType.STICKY_BALLOON, true) private val DISABLED_UPDATE = "disabled_update.txt" - private val NO_PLATFORM_UPDATE = "ide.no.platform.update" private var ourDisabledToUpdatePlugins: MutableSet? = null private val ourAdditionalRequestOptions = hashMapOf() @@ -156,7 +154,7 @@ object UpdateChecker { } private fun checkPlatformUpdate(settings: UpdateSettings): CheckForUpdateResult { - if (SystemProperties.getBooleanProperty(NO_PLATFORM_UPDATE, false)) { + if (!settings.isPlatformUpdateEnabled) { return CheckForUpdateResult(UpdateStrategy.State.NOTHING_LOADED, null) } diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java index 2770eb01e39c..d3a8872d66eb 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -20,6 +20,7 @@ import com.intellij.openapi.components.*; import com.intellij.openapi.updateSettings.UpdateStrategyCustomization; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.SmartList; +import com.intellij.util.SystemProperties; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.net.NetUtils; import com.intellij.util.xmlb.annotations.CollectionBean; @@ -27,8 +28,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.List; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -61,8 +62,13 @@ public class UpdateSettings implements PersistentStateComponent unscramble.unscrambled.deadlock.tab= updates.checking.progress=Checking for Updates -updates.checking.platform=Checking for platform updates +updates.checking.platform=Checking for IDE updates updates.checking.plugins=Checking for plugin updates updates.error.connection.title=Connection Error updates.error.connection.failed=Connection failed ({0}). Please check network connection and try again. updates.error.plugin.description.failed=Failed to load plugin descriptions from: \"{0}\" -update.notifications.title=Platform and Plugin Updates +update.notifications.title=IDE and Plugin Updates updates.channel.bundled.key=The new version has an expiration date and does not require a license. updates.paid.upgrade=You can evaluate the new version for {0} days, or buy it online. updates.fallback.build=You have a perpetual fallback license for the new version. @@ -933,7 +933,9 @@ updates.external.progress=Fetching available updates for external components updates.external.ready.message=The following component{0,choice,1# is|2#s are} ready to update: {1} updates.external.error.message=Failed to check for updates to {0}: {1} updates.plugins.ready.message=The following plugin{0,choice,1# is|2#s are} ready to update: {1} -updates.no.updates.message=You already have the latest version of {0} installed. +updates.no.updates.message=You already have the latest version of {0} and plugins installed. +updates.no.updates.plugins.message=You already have the latest version of plugins installed.
\ + IDE updates are managed externally and weren't checked. updates.plugins.ready.header=Plugins from configured hosts are ready to update.
\ Check plugins you want to update. updates.configure.label=To configure automatic update settings, see the Updates dialog of your IDE {0}. From d02266c7a75763895de4c492c4d7543edaf0f7c4 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 6 Apr 2017 21:01:40 +0200 Subject: [PATCH 019/111] Cleanup (typos; deprecation; formatting) --- .../updateSettings/impl/UpdateCheckerComponent.java | 2 +- .../openapi/updateSettings/impl/UpdateSettings.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerComponent.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerComponent.java index ad757e76af18..cfd5d3786303 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerComponent.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerComponent.java @@ -112,7 +112,7 @@ public class UpdateCheckerComponent implements Disposable, ApplicationComponent @Override public void appFrameCreated(String[] commandLineArgs, @NotNull Ref willOpenProject) { BuildNumber currentBuild = ApplicationInfo.getInstance().getBuild(); - BuildNumber lastBuildChecked = BuildNumber.fromString(mySettings.getLasBuildChecked()); + BuildNumber lastBuildChecked = BuildNumber.fromString(mySettings.getLastBuildChecked()); long timeSinceLastCheck = max(System.currentTimeMillis() - mySettings.getLastTimeChecked(), 0); if (lastBuildChecked == null || currentBuild.compareTo(lastBuildChecked) > 0 || timeSinceLastCheck >= CHECK_INTERVAL) { diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java index d3a8872d66eb..ea6ccd3899d3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateSettings.java @@ -82,7 +82,7 @@ public class UpdateSettings implements PersistentStateComponent getActiveChannels() { UpdateStrategyCustomization tweaker = UpdateStrategyCustomization.getInstance(); return Stream.of(ChannelStatus.values()) - .filter((ch) -> ch == ChannelStatus.EAP || ch == ChannelStatus.RELEASE || tweaker.isChannelActive(ch)) + .filter(ch -> ch == ChannelStatus.EAP || ch == ChannelStatus.RELEASE || tweaker.isChannelActive(ch)) .collect(Collectors.toList()); } @@ -179,13 +179,13 @@ public class UpdateSettings implements PersistentStateComponent - /** @deprecated use {@link #getSelectedChannelStatus()} (to be removed in IDEA 17) */ + /** @deprecated use {@link #getSelectedChannelStatus()} (to be removed in IDEA 2018) */ @SuppressWarnings("unused") public String getUpdateChannelType() { return myState.UPDATE_CHANNEL_TYPE; } - /** @deprecated use {@link #setSelectedChannelStatus(ChannelStatus)} (to be removed in IDEA 17) */ + /** @deprecated use {@link #setSelectedChannelStatus(ChannelStatus)} (to be removed in IDEA 2018) */ @SuppressWarnings("unused") public void setUpdateChannelType(@NotNull String value) { myState.UPDATE_CHANNEL_TYPE = value; From d9f6b155d29c8d01251565b4389f584748c96d75 Mon Sep 17 00:00:00 2001 From: Eldar Abusalimov Date: Thu, 6 Apr 2017 22:22:27 +0300 Subject: [PATCH 020/111] execution: Escape Cygwin glob special chars: [*?\[{}~] + [()'] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These characters enable extended POSIX globbing on Cygwin. References: https://github.com/mirror/newlib-cygwin/blob/961a6909d950a0423d0e70e8a64187fb7d535c7d/winsup/cygwin/dcrt0.cc#L208-L209 if (*word != '~' && strpbrk (word, "?*[\"\'(){}") == NULL) return 0; Fixes:   - IDEA-165122 git stash broken   - IDEA-54753 Git: Unstash changes: Apply and pop actions fail. --- .../execution/GeneralCommandLineTest.java | 29 +++++++++++++++++++ .../intellij/execution/CommandLineUtil.java | 21 +++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/platform/platform-tests/testSrc/com/intellij/execution/GeneralCommandLineTest.java b/platform/platform-tests/testSrc/com/intellij/execution/GeneralCommandLineTest.java index 0535013b7719..b8ae88f82f17 100644 --- a/platform/platform-tests/testSrc/com/intellij/execution/GeneralCommandLineTest.java +++ b/platform/platform-tests/testSrc/com/intellij/execution/GeneralCommandLineTest.java @@ -39,6 +39,7 @@ import java.util.*; import static com.intellij.openapi.util.Pair.pair; import static com.intellij.util.containers.ContainerUtil.newHashMap; import static org.junit.Assert.*; +import static org.junit.Assume.assumeNotNull; import static org.junit.Assume.assumeTrue; public class GeneralCommandLineTest { @@ -101,6 +102,20 @@ public class GeneralCommandLineTest { "\\?", "\"?\"", "*.???", // ^ the Xmas tree above is to catch at least one file matching those globs + "stash@{1}", + "{}", + "{1}", + "{1,2}{a,b}", + "test[Src][Src][Src]", + "[t]estData", + "~", + "'~'", + "'single-quoted'", + "''", + "C:\\cygwin*", + "C:\\cygwin{,64}", + "C:\\cygwin{,64}\\printf.e[x]e", + "\\\\dos\\path\\{1,2}{a,b}", }; @SuppressWarnings("SpellCheckingInspection") private static final String UNICODE_RU = "Юникоде"; @@ -271,6 +286,20 @@ public class GeneralCommandLineTest { } } + @Test(timeout = 60000) + public void passingArgumentsToCygwinPrintf() throws Exception { + assumeTrue(SystemInfo.isWindows); + File cygwinPrintf = FileUtil.findFirstThatExist("C:\\cygwin\\bin\\printf.exe", + "C:\\cygwin64\\bin\\printf.exe"); + assumeNotNull(cygwinPrintf); + + for (String argument : ARGUMENTS) { + GeneralCommandLine commandLine = createCommandLine(cygwinPrintf.getPath(), "[%s]\\\\n", argument); + String output = execAndGetOutput(commandLine); + assertEquals(commandLine.getPreparedCommandLine(), filterExpectedOutput("[" + argument + "]\n"), output); + } + } + @Test(timeout = 60000) public void unicodeParameters() throws Exception { assumeTrue(UNICODE != null); diff --git a/platform/util/src/com/intellij/execution/CommandLineUtil.java b/platform/util/src/com/intellij/execution/CommandLineUtil.java index b484e4ef95c7..5969f9a139d3 100644 --- a/platform/util/src/com/intellij/execution/CommandLineUtil.java +++ b/platform/util/src/com/intellij/execution/CommandLineUtil.java @@ -33,7 +33,7 @@ public class CommandLineUtil { private static final Pattern WIN_BACKSLASHES_PRECEDING_QUOTE = Pattern.compile("(\\\\+)(?=\"|$)"); private static final Pattern WIN_CARET_SPECIAL = Pattern.compile("[&<>()@^|]"); - private static final Pattern WIN_QUOTE_SPECIAL = Pattern.compile("[ \t\"*?]"); + private static final Pattern WIN_QUOTE_SPECIAL = Pattern.compile("[ \t\"*?\\[{}~()\']"); // + glob [*?] + Cygwin glob [*?\[{}~] + [()'] private static final Pattern WIN_QUIET_COMMAND = Pattern.compile("((?:@\\s*)++)(.*)", Pattern.CASE_INSENSITIVE); private static final char Q = '\"'; @@ -100,6 +100,25 @@ public class CommandLineUtil { * -> ["C:\Program Files\\" "\"backslash quote\\\""] * * + * *** Besides the rules above, double quotes escaping is also used to prevent CRT from glob-expanding the arguments + * containing the [*?] special chars. + * + * Cygwin note: + * + * Additionally, we also use double quotes to escape POSIX glob special chars that otherwise are processed + * by Cygwin CRT. These chars [*?\[{}~] and [()'] enable extended POSIX globbing unless the CYGWIN=noglob + * variable is set, which we can't rely upon anyway because the behavior of 'noglob' doesn't conform to the + * standard command line quoting rules (for example, it expands [\\\"] to [\\\] instead of the expected [\"]). + * + * This is enabled unconditionally on Windows, that is, no attempt is made to detect that we indeed run under + * Cygwin. Although it might be checked as well (yet in some clumsy way, for example, by looking up cygwin-1.dll + * in PATH), it doesn't make much sense since such check wouldn't be a 100% reliable solution anyway + * (the executable may still run without linking to Cygwin CRT, even if the latter is in PATH). + * + * Anyway, escaping yet another set of special chars is harmless as long as the executable uses the standard + * Windows CRT parameter quoting conventions, which is almost always the case. + * + * * *** In case a command line is wrapped using CMD.EXE call (that is, `cmd /d /c call executable args...`, which * is quite common), additional escaping rules apply. * From cb500983a662c9de5121a92e894acd3204581449 Mon Sep 17 00:00:00 2001 From: Alexey Gopachenko Date: Thu, 6 Apr 2017 15:53:57 +0200 Subject: [PATCH 021/111] PHP nicer folding error diff! (cherry picked from commit 34601b8) --- .../fixtures/impl/CodeInsightTestFixtureImpl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 27835eebd26f..b9137b5a4f44 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -1624,8 +1624,10 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig private void testFoldingRegions(@NotNull String verificationFileName, @Nullable String destinationFileName, boolean doCheckCollapseStatus) { String expectedContent; - try { - expectedContent = FileUtil.loadFile(new File(verificationFileName)); + final File verificationFile; + try { + verificationFile = new File(verificationFileName); + expectedContent = FileUtil.loadFile(verificationFile); } catch (IOException e) { throw new RuntimeException(e); @@ -1650,7 +1652,9 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig } } final String actual = getFoldingDescription(doCheckCollapseStatus); - assertEquals(expectedContent, actual); + if(!expectedContent.equals(actual)) { + throw new FileComparisonFailure(verificationFile.getName(), expectedContent, actual, verificationFile.getPath()); + } } @Override From f3259b8405b95ee3a3b951df2707b471561d808d Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 6 Apr 2017 22:33:12 +0200 Subject: [PATCH 022/111] add ProgressIndicatorListener#installToProgress and deprecate ProgressWindowWithNotification --- .../JavaWithRuntimeCastSurrounder.java | 4 ++-- .../engine/DebuggerManagerThreadImpl.java | 10 ++++++++-- .../debugger/engine/JavaValueModifier.java | 4 ++-- .../ui/breakpoints/MethodBreakpoint.java | 10 +++++----- .../util/ProgressIndicatorListener.java | 18 ++++++++++++++++++ .../util/ProgressWindowWithNotification.java | 17 +++-------------- 6 files changed, 38 insertions(+), 25 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java b/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java index 730a0d7241bd..06312d385d56 100644 --- a/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java +++ b/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java @@ -28,7 +28,7 @@ import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.util.ProgressWindowWithNotification; +import com.intellij.openapi.progress.util.ProgressWindow; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; @@ -63,7 +63,7 @@ public class JavaWithRuntimeCastSurrounder extends JavaExpressionSurrounder { DebuggerContextImpl debuggerContext = (DebuggerManagerEx.getInstanceEx(project)).getContext(); DebuggerSession debuggerSession = debuggerContext.getDebuggerSession(); if (debuggerSession != null) { - final ProgressWindowWithNotification progressWindow = new ProgressWindowWithNotification(true, expr.getProject()); + final ProgressWindow progressWindow = new ProgressWindow(true, expr.getProject()); SurroundWithCastWorker worker = new SurroundWithCastWorker(editor, expr, debuggerContext, progressWindow); progressWindow.setTitle(DebuggerBundle.message("title.evaluating")); debuggerContext.getDebugProcess().getManagerThread().startProgress(worker, progressWindow); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java index 514f2622316a..55b308317020 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebuggerManagerThreadImpl.java @@ -26,6 +26,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.util.ProgressIndicatorListenerAdapter; +import com.intellij.openapi.progress.util.ProgressWindow; import com.intellij.openapi.progress.util.ProgressWindowWithNotification; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; @@ -160,13 +161,18 @@ public class DebuggerManagerThreadImpl extends InvokeAndWaitThread ProgressManager.getInstance().runProcess(() -> invokeAndWait(command), progressWindow)); diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java index dc1cbdd76922..fd37398eed70 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java @@ -27,7 +27,7 @@ import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerSession; import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl; import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl; -import com.intellij.openapi.progress.util.ProgressWindowWithNotification; +import com.intellij.openapi.progress.util.ProgressWindow; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; @@ -197,7 +197,7 @@ public abstract class JavaValueModifier extends XValueModifier { } protected void set(@NotNull final String expression, final XModificationCallback callback, final DebuggerContextImpl debuggerContext, final SetValueRunnable setValueRunnable) { - final ProgressWindowWithNotification progressWindow = new ProgressWindowWithNotification(true, debuggerContext.getProject()); + final ProgressWindow progressWindow = new ProgressWindow(true, debuggerContext.getProject()); final EvaluationContextImpl evaluationContext = myJavaValue.getEvaluationContext(); SuspendContextCommandImpl askSetAction = new DebuggerContextCommandImpl(debuggerContext) { diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java index da776d39b2bf..4c9e8cb5a2d4 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/MethodBreakpoint.java @@ -40,7 +40,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.util.ProgressWindowWithNotification; +import com.intellij.openapi.progress.util.ProgressWindow; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; @@ -135,15 +135,15 @@ public class MethodBreakpoint extends BreakpointWithHighlighter indicatorRef = new AtomicReference<>(); + AtomicReference indicatorRef = new AtomicReference<>(); ApplicationManager.getApplication().invokeAndWait( () -> { - ProgressWindowWithNotification progress = - new ProgressWindowWithNotification(true, false, debugProcess.getProject(), "Cancel emulation"); + ProgressWindow progress = + new ProgressWindow(true, false, debugProcess.getProject(), "Cancel emulation"); progress.setDelayInMillis(2000); indicatorRef.set(progress); }); - ProgressWindowWithNotification indicator = indicatorRef.get(); + ProgressWindow indicator = indicatorRef.get(); AtomicBoolean changed = new AtomicBoolean(); XBreakpointListener> listener = new XBreakpointListener>() { diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressIndicatorListener.java b/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressIndicatorListener.java index b82961fbe4e0..2c6e71d94810 100644 --- a/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressIndicatorListener.java +++ b/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressIndicatorListener.java @@ -15,6 +15,8 @@ */ package com.intellij.openapi.progress.util; +import com.intellij.openapi.wm.ex.ProgressIndicatorEx; + /** * @author lex */ @@ -22,4 +24,20 @@ public interface ProgressIndicatorListener { void cancelled(); void stopped(); + + default void installToProgress(ProgressIndicatorEx progress) { + progress.addStateDelegate(new AbstractProgressIndicatorExBase(){ + @Override + public void cancel() { + super.cancel(); + cancelled(); + } + + @Override + public void stop() { + super.stop(); + stopped(); + } + }); + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressWindowWithNotification.java b/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressWindowWithNotification.java index 8d5be53460d1..adeeef9dbcba 100644 --- a/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressWindowWithNotification.java +++ b/platform/platform-impl/src/com/intellij/openapi/progress/util/ProgressWindowWithNotification.java @@ -16,11 +16,12 @@ package com.intellij.openapi.progress.util; import com.intellij.openapi.project.Project; +import com.intellij.openapi.wm.ex.ProgressIndicatorEx; import javax.swing.*; /** - * @author lex + * @deprecated use {@link ProgressWindow} and {@link ProgressIndicatorListener#installToProgress(ProgressIndicatorEx)} */ public class ProgressWindowWithNotification extends ProgressWindow { public ProgressWindowWithNotification(boolean shouldShowCancel, Project project) { @@ -40,19 +41,7 @@ public class ProgressWindowWithNotification extends ProgressWindow { } public void addListener(final ProgressIndicatorListener listener) { - addStateDelegate(new AbstractProgressIndicatorExBase(){ - @Override - public void cancel() { - super.cancel(); - listener.cancelled(); - } - - @Override - public void stop() { - super.stop(); - listener.stopped(); - } - }); + listener.installToProgress(this); } } From 412d071d08f317da853fd18f2e145b5a2d4cfe51 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Thu, 6 Apr 2017 12:50:23 +0200 Subject: [PATCH 023/111] add fixes to change expected type when inference fails due to it (IDEA-162846) --- .../impl/analysis/HighlightMethodUtil.java | 32 +++++++++++++++++++ ...FailedInferenceDueToWrongExpectedType.java | 10 ++++++ ...renceDueToWrongExpectedTypeAssignment.java | 11 +++++++ ...ceDueToWrongExpectedTypeNotApplicable.java | 15 +++++++++ ...FailedInferenceDueToWrongExpectedType.java | 10 ++++++ ...renceDueToWrongExpectedTypeAssignment.java | 11 +++++++ ...ceDueToWrongExpectedTypeNotApplicable.java | 15 +++++++++ 7 files changed, 104 insertions(+) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/afterFailedInferenceDueToWrongExpectedType.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/afterFailedInferenceDueToWrongExpectedTypeAssignment.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/afterFailedInferenceDueToWrongExpectedTypeNotApplicable.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/beforeFailedInferenceDueToWrongExpectedType.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/beforeFailedInferenceDueToWrongExpectedTypeAssignment.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/beforeFailedInferenceDueToWrongExpectedTypeNotApplicable.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 7e9e22850c1e..5b4b97d96ecf 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -390,6 +390,7 @@ public class HighlightMethodUtil { if (highlightInfo != null) { registerMethodCallIntentions(highlightInfo, methodCall, list, resolveHelper); registerMethodReturnFixAction(highlightInfo, (MethodCandidateInfo)resolveResult, methodCall); + registerTargetTypeFixesBasedOnApplicabilityInference(methodCall, (MethodCandidateInfo)resolveResult, (PsiMethod)resolved, highlightInfo); } } } @@ -430,6 +431,7 @@ public class HighlightMethodUtil { if (highlightInfo != null) { registerMethodCallIntentions(highlightInfo, methodCall, list, resolveHelper); registerMethodReturnFixAction(highlightInfo, candidateInfo, methodCall); + registerTargetTypeFixesBasedOnApplicabilityInference(methodCall, candidateInfo, resolvedMethod, highlightInfo); } } else { @@ -472,6 +474,36 @@ public class HighlightMethodUtil { return highlightInfo; } + private static void registerTargetTypeFixesBasedOnApplicabilityInference(@NotNull PsiMethodCallExpression methodCall, + MethodCandidateInfo resolveResult, + PsiMethod resolved, + HighlightInfo highlightInfo) { + PsiElement parent = PsiUtil.skipParenthesizedExprUp(methodCall.getParent()); + PsiVariable variable = null; + if (parent instanceof PsiVariable) { + variable = (PsiVariable)parent; + } + else if (parent instanceof PsiAssignmentExpression) { + PsiExpression lExpression = ((PsiAssignmentExpression)parent).getLExpression(); + if (lExpression instanceof PsiReferenceExpression) { + PsiElement resolve = ((PsiReferenceExpression)lExpression).resolve(); + if (resolve instanceof PsiVariable) { + variable = (PsiVariable)resolve; + } + } + } + + if (variable != null) { + PsiType rType = methodCall.getType(); + if (rType != null && !variable.getType().isAssignableFrom(rType)) { + PsiType expectedTypeByApplicabilityConstraints = resolveResult.getSubstitutor(false).substitute(resolved.getReturnType()); + if (expectedTypeByApplicabilityConstraints != null && !expectedTypeByApplicabilityConstraints.equals(rType)) { + HighlightUtil.registerChangeVariableTypeFixes(variable, expectedTypeByApplicabilityConstraints, methodCall, highlightInfo); + } + } + } + } + /* see also PsiReferenceExpressionImpl.hasValidQualifier() */ @Nullable private static String checkStaticInterfaceMethodCallQualifier(PsiReferenceExpression ref, PsiElement scope, PsiClass containingClass) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/afterFailedInferenceDueToWrongExpectedType.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/afterFailedInferenceDueToWrongExpectedType.java new file mode 100644 index 000000000000..ccea5e7c4883 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/afterFailedInferenceDueToWrongExpectedType.java @@ -0,0 +1,10 @@ +// "Change variable 'foo' type to 'java.util.List'" "true" + +import java.util.Arrays; +import java.util.List; + +class MyClass { + void bar() { + List foo = Arrays.asList("a"); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/afterFailedInferenceDueToWrongExpectedTypeAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/afterFailedInferenceDueToWrongExpectedTypeAssignment.java new file mode 100644 index 000000000000..a7297a2d5e66 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/afterFailedInferenceDueToWrongExpectedTypeAssignment.java @@ -0,0 +1,11 @@ +// "Change variable 'foo' type to 'java.util.List'" "true" + +import java.util.Arrays; +import java.util.List; + +class MyClass { + void bar() { + List foo; + foo = (Arrays.asList("a")); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/afterFailedInferenceDueToWrongExpectedTypeNotApplicable.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/afterFailedInferenceDueToWrongExpectedTypeNotApplicable.java new file mode 100644 index 000000000000..5861eb786683 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/afterFailedInferenceDueToWrongExpectedTypeNotApplicable.java @@ -0,0 +1,15 @@ +// "Change variable 'foo' type to 'java.lang.String'" "true" + +import java.util.List; +import java.util.Set; + +class MyClass { + public static void sort(final List list) { + String foo = (findStart(list)); + } + + private static V findStart(List result) { + return result.get(0); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/beforeFailedInferenceDueToWrongExpectedType.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/beforeFailedInferenceDueToWrongExpectedType.java new file mode 100644 index 000000000000..802171f834a2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/beforeFailedInferenceDueToWrongExpectedType.java @@ -0,0 +1,10 @@ +// "Change variable 'foo' type to 'java.util.List'" "true" + +import java.util.Arrays; +import java.util.List; + +class MyClass { + void bar() { + String[] foo = Arrays.asList("a"); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/beforeFailedInferenceDueToWrongExpectedTypeAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/beforeFailedInferenceDueToWrongExpectedTypeAssignment.java new file mode 100644 index 000000000000..42be9d9e4e0e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/beforeFailedInferenceDueToWrongExpectedTypeAssignment.java @@ -0,0 +1,11 @@ +// "Change variable 'foo' type to 'java.util.List'" "true" + +import java.util.Arrays; +import java.util.List; + +class MyClass { + void bar() { + String[] foo; + foo = (Arrays.asList("a")); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/beforeFailedInferenceDueToWrongExpectedTypeNotApplicable.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/beforeFailedInferenceDueToWrongExpectedTypeNotApplicable.java new file mode 100644 index 000000000000..f9612e9aa742 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/variableType/beforeFailedInferenceDueToWrongExpectedTypeNotApplicable.java @@ -0,0 +1,15 @@ +// "Change variable 'foo' type to 'java.lang.String'" "true" + +import java.util.List; +import java.util.Set; + +class MyClass { + public static void sort(final List list) { + Set foo = (findStart(list)); + } + + private static V findStart(List result) { + return result.get(0); + } + +} \ No newline at end of file From acffacf0adca2c654dedc1d736027fc81c44e69b Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Thu, 6 Apr 2017 17:54:30 +0200 Subject: [PATCH 024/111] intention to extract lambda body to method and convert to method reference (IDEA-123262) --- .../src/META-INF/IntentionPowerPack.xml | 5 + .../siyeh/IntentionPowerPackBundle.properties | 1 + .../ExtractToMethodReferenceIntention.java | 222 ++++++++++++++++++ .../after.java.template | 10 + .../before.java.template | 8 + .../description.html | 5 + .../ConvertableToMethodReference.java | 8 + .../OverloadedMethodSameName.java | 9 + .../OverloadedMethodSameName_after.java | 13 + .../RequiredTypeParameter.java | 11 + .../RequiredTypeParameter_after.java | 13 + .../SameSignatureMethodExists.java | 9 + .../SameSignatureMethodExists_after.java | 13 + .../UnableToCreateStatic.java | 8 + .../UnableToCreateStatic_after.java | 12 + .../UnusedParameterToConfirmSignature.java | 8 + ...usedParameterToConfirmSignature_after.java | 12 + .../UsedLocalVariables.java | 9 + .../ExtractToMethodReferenceTest.java | 61 +++++ 19 files changed, 437 insertions(+) create mode 100644 plugins/IntentionPowerPak/src/com/siyeh/ipp/functional/ExtractToMethodReferenceIntention.java create mode 100644 plugins/IntentionPowerPak/src/intentionDescriptions/ExtractToMethodReferenceIntention/after.java.template create mode 100644 plugins/IntentionPowerPak/src/intentionDescriptions/ExtractToMethodReferenceIntention/before.java.template create mode 100644 plugins/IntentionPowerPak/src/intentionDescriptions/ExtractToMethodReferenceIntention/description.html create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/ConvertableToMethodReference.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/OverloadedMethodSameName.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/OverloadedMethodSameName_after.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/RequiredTypeParameter.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/RequiredTypeParameter_after.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/SameSignatureMethodExists.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/SameSignatureMethodExists_after.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnableToCreateStatic.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnableToCreateStatic_after.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnusedParameterToConfirmSignature.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnusedParameterToConfirmSignature_after.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UsedLocalVariables.java create mode 100644 plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/functional/ExtractToMethodReferenceTest.java diff --git a/plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml b/plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml index c620ebf524b8..b7613144d272 100644 --- a/plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml +++ b/plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml @@ -522,5 +522,10 @@ com.siyeh.IntentionPowerPackBundle intention.category.other + + com.siyeh.ipp.functional.ExtractToMethodReferenceIntention + com.siyeh.IntentionPowerPackBundle + intention.category.control.flow + diff --git a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties index 47a682d8c0a6..29f54d3b2858 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties +++ b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties @@ -2,6 +2,7 @@ plugin.IntentionPowerPack.description=Adds over 80 new intention actions for IDE replace.fully.qualified.name.with.import.intention.name=Replace qualified name with 'import' replace.fully.qualified.name.with.import.intention.family.name=Replace Qualified Name with Import replace.if.with.switch.intention.name=Replace 'if' with 'switch' +extract.to.method.reference.intention.name=Extract to method reference replace.if.with.switch.intention.family.name=Replace If with Switch merge.parallel.ifs.intention.name=Merge 'if's merge.parallel.ifs.intention.family.name=Merge Parallel Ifs diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/functional/ExtractToMethodReferenceIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/functional/ExtractToMethodReferenceIntention.java new file mode 100644 index 000000000000..d81abab94969 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/functional/ExtractToMethodReferenceIntention.java @@ -0,0 +1,222 @@ +/* + * Copyright 2000-2017 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.siyeh.ipp.functional; + +import com.intellij.codeInsight.CodeInsightUtilCore; +import com.intellij.codeInsight.intention.BaseElementAtCaretIntentionAction; +import com.intellij.codeInspection.LambdaCanBeMethodReferenceInspection; +import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pass; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.extractMethod.AbstractExtractDialog; +import com.intellij.refactoring.extractMethod.ControlFlowWrapper; +import com.intellij.refactoring.extractMethod.ExtractMethodProcessor; +import com.intellij.refactoring.extractMethod.PrepareFailedException; +import com.intellij.refactoring.rename.RenamePsiElementProcessor; +import com.intellij.refactoring.rename.inplace.MemberInplaceRenamer; +import com.intellij.refactoring.util.VariableData; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ObjectUtils; +import com.intellij.util.text.UniqueNameGenerator; +import com.siyeh.IntentionPowerPackBundle; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.List; + +public class ExtractToMethodReferenceIntention extends BaseElementAtCaretIntentionAction { + @NotNull + @Override + public String getText() { + return getFamilyName(); + } + + @NotNull + @Override + public String getFamilyName() { + return IntentionPowerPackBundle.message("extract.to.method.reference.intention.name"); + } + + @Override + public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) { + final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class, false); + if (lambdaExpression != null) { + PsiElement body = lambdaExpression.getBody(); + if (body == null) return false; + PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType(); + if (functionalInterfaceType == null) return false; + PsiExpression asMethodReference = LambdaCanBeMethodReferenceInspection + .canBeMethodReferenceProblem(body, lambdaExpression.getParameterList().getParameters(), functionalInterfaceType, null); + if (asMethodReference != null) return false; + try { + PsiElement[] toExtract = body instanceof PsiCodeBlock ? ((PsiCodeBlock)body).getStatements() : new PsiElement[] {body}; + ControlFlowWrapper wrapper = new ControlFlowWrapper(project, body, toExtract); + wrapper.prepareExitStatements(toExtract, body); + PsiVariable[] outputVariables = wrapper.getOutputVariables(); + List inputVariables = wrapper.getInputVariables(body, toExtract, outputVariables); + return inputVariables.stream().allMatch(variable -> variable instanceof PsiParameter && ((PsiParameter)variable).getDeclarationScope() == lambdaExpression); + } + catch (PrepareFailedException ignored) { } + catch (ControlFlowWrapper.ExitStatementsNotSameException ignored) { } + } + return false; + } + + @Override + public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { + final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class, false); + if (lambdaExpression != null) { + PsiElement body = lambdaExpression.getBody(); + if (body != null) { + PsiElement[] elements = body instanceof PsiCodeBlock ? ((PsiCodeBlock)body).getStatements() : new PsiElement[] {body}; + PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(lambdaExpression.getFunctionalInterfaceType()); + String initialMethodName = interfaceMethod != null ? interfaceMethod.getName() : "name"; + ExtractMethodProcessor methodProcessor = new ExtractMethodProcessor(project, editor, elements, null, getFamilyName(), null, null) { + @Override + public boolean showDialog() { + apply(new MyExtractMethodDialog(myTargetClass, lambdaExpression, myCanBeStatic, initialMethodName)); + return true; + } + }; + + try { + methodProcessor.prepare(); + } + catch (PrepareFailedException e) { + return; + } + methodProcessor.showDialog(); + WriteAction.run(() -> { + methodProcessor.doExtract(); + PsiExpression expression = LambdaCanBeMethodReferenceInspection.replaceLambdaWithMethodReference(lambdaExpression); + if (expression instanceof PsiMethodReferenceExpression) { + PsiMethod method = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(methodProcessor.getExtractedMethod()); + + PsiElement refElement = ((PsiMethodReferenceExpression)expression).getReferenceNameElement(); + PsiIdentifier nameIdentifier = method.getNameIdentifier(); + if (nameIdentifier == null) return; + + //try to navigate to reference name + editor.getCaretModel().moveToOffset(ObjectUtils.notNull(refElement, nameIdentifier).getTextOffset()); + + final RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(method); + if (!processor.isInplaceRenameSupported()) { + return; + } + List suggestedNames = new ArrayList<>(); + suggestedNames.add(method.getName()); + processor.substituteElementToRename(method, editor, new Pass() { + @Override + public void pass(PsiElement substitutedElement) { + final MemberInplaceRenamer renamer = new MemberInplaceRenamer(method, substitutedElement, editor); + final LinkedHashSet nameSuggestions = new LinkedHashSet<>(suggestedNames); + renamer.performInplaceRefactoring(nameSuggestions); + } + }); + } + }); + } + } + } + + @Nullable + @Override + public PsiElement getElementToMakeWritable(@NotNull PsiFile currentFile) { + return currentFile; + } + + @Override + public boolean startInWriteAction() { + return false; + } + + private static class MyExtractMethodDialog implements AbstractExtractDialog { + private final String myTargetMethodName; + private final boolean myCanBeStatic; + private final VariableData[] myVariableData; + + public MyExtractMethodDialog(@NotNull PsiClass targetClass, + PsiLambdaExpression lambdaExpression, + boolean canBeStatic, + String initialMethodName) { + myVariableData = Arrays.stream(lambdaExpression.getParameterList().getParameters()) + .map(parameter -> { + VariableData data = new VariableData(parameter); + data.passAsParameter = true; + data.name = parameter.getName(); + return data; + }) + .toArray(VariableData[]::new); + myCanBeStatic = canBeStatic; + PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(targetClass.getProject()); + String parameters = "(" + StringUtil.join(myVariableData, data -> data.type.getCanonicalText() + " " + data.name, ", ") + "){}"; + myTargetMethodName = UniqueNameGenerator.generateUniqueName(initialMethodName, + methodName -> { + String methodText = "private void " + methodName + parameters; + PsiMethod patternMethod = elementFactory.createMethodFromText(methodText, lambdaExpression); + return targetClass.findMethodBySignature(patternMethod, true) == null; + }); + + } + + @Override + public String getChosenMethodName() { + return myTargetMethodName; + } + + @Override + public VariableData[] getChosenParameters() { + return myVariableData; + } + + @NotNull + @Override + public String getVisibility() { + return PsiModifier.PRIVATE; + } + + @Override + public boolean isMakeStatic() { + return myCanBeStatic; + } + + @Override + public boolean isChainedConstructor() { + return false; + } + + @Override + public PsiType getReturnType() { + return null; + } + + @Override + public void show() {} + + @Override + public boolean isOK() { + return true; + } + } +} + diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/ExtractToMethodReferenceIntention/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/ExtractToMethodReferenceIntention/after.java.template new file mode 100644 index 000000000000..5ab0b0a67ad9 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/ExtractToMethodReferenceIntention/after.java.template @@ -0,0 +1,10 @@ +class X { + { + JButton b = new JButton(); + b.addActionListener(this::clicked); + } + + private void clicked(ActionEvent e) { + System.out.println("clicked"); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/ExtractToMethodReferenceIntention/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/ExtractToMethodReferenceIntention/before.java.template new file mode 100644 index 000000000000..2070aa284793 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/ExtractToMethodReferenceIntention/before.java.template @@ -0,0 +1,8 @@ +class X { + { + JButton b = new JButton(); + b.addActionListener(e -> { + System.out.println("clicked"); + }); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/ExtractToMethodReferenceIntention/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/ExtractToMethodReferenceIntention/description.html new file mode 100644 index 000000000000..32b71eec8529 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/ExtractToMethodReferenceIntention/description.html @@ -0,0 +1,5 @@ + + +

Intention to extract the lambda body to a method and convert lambda to method reference.

+ + \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/ConvertableToMethodReference.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/ConvertableToMethodReference.java new file mode 100644 index 000000000000..1dd9b0534de5 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/ConvertableToMethodReference.java @@ -0,0 +1,8 @@ +interface I { + void m(int i); +} +class B { + { + I i = i1 -> System.out.println(i1); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/OverloadedMethodSameName.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/OverloadedMethodSameName.java new file mode 100644 index 000000000000..e9aff6e178b6 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/OverloadedMethodSameName.java @@ -0,0 +1,9 @@ +interface I { + void m(int i); +} +class B { + void m() {} + { + I i = i1 -> System.out.println(i1 + ""); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/OverloadedMethodSameName_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/OverloadedMethodSameName_after.java new file mode 100644 index 000000000000..e8ef9a39e56f --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/OverloadedMethodSameName_after.java @@ -0,0 +1,13 @@ +interface I { + void m(int i); +} +class B { + private static void m(int i1) { + System.out.println(i1 + ""); + } + + void m() {} + { + I i = B::m; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/RequiredTypeParameter.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/RequiredTypeParameter.java new file mode 100644 index 000000000000..0463b280d9fd --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/RequiredTypeParameter.java @@ -0,0 +1,11 @@ +interface I { + void m(T t); +} +class B { + void n(){ + I i = i1 -> { + System.out.println(i1); + System.out.println(i1); + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/RequiredTypeParameter_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/RequiredTypeParameter_after.java new file mode 100644 index 000000000000..3cb9fc2042d0 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/RequiredTypeParameter_after.java @@ -0,0 +1,13 @@ +interface I { + void m(T t); +} +class B { + private static void m(N i1) { + System.out.println(i1); + System.out.println(i1); + } + + void n(){ + I i = B::m + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/SameSignatureMethodExists.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/SameSignatureMethodExists.java new file mode 100644 index 000000000000..9eec7e203043 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/SameSignatureMethodExists.java @@ -0,0 +1,9 @@ +interface I { + void m(int i); +} +class B { + void m(int i) {} + { + I i = i1 -> System.out.println(i1 + ""); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/SameSignatureMethodExists_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/SameSignatureMethodExists_after.java new file mode 100644 index 000000000000..5a4e434fb0fa --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/SameSignatureMethodExists_after.java @@ -0,0 +1,13 @@ +interface I { + void m(int i); +} +class B { + private static void m2(int i1) { + System.out.println(i1 + ""); + } + + void m(int i) {} + { + I i = B::m2; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnableToCreateStatic.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnableToCreateStatic.java new file mode 100644 index 000000000000..d9cd24b639a6 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnableToCreateStatic.java @@ -0,0 +1,8 @@ +interface I { + void m(int i); +} +class B { + class X { + I i = i1 -> System.out.println(""); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnableToCreateStatic_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnableToCreateStatic_after.java new file mode 100644 index 000000000000..4f5accb0fa9a --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnableToCreateStatic_after.java @@ -0,0 +1,12 @@ +interface I { + void m(int i); +} +class B { + class X { + private void m(int i1) { + System.out.println(""); + } + + I i = this::m; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnusedParameterToConfirmSignature.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnusedParameterToConfirmSignature.java new file mode 100644 index 000000000000..525970547c9a --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnusedParameterToConfirmSignature.java @@ -0,0 +1,8 @@ +interface I { + void m(int i); +} +class B { + { + I i = i1 -> System.out.println(""); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnusedParameterToConfirmSignature_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnusedParameterToConfirmSignature_after.java new file mode 100644 index 000000000000..216cd22ca70b --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnusedParameterToConfirmSignature_after.java @@ -0,0 +1,12 @@ +interface I { + void m(int i); +} +class B { + private static void m(int i1) { + System.out.println(""); + } + + { + I i = B::m; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UsedLocalVariables.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UsedLocalVariables.java new file mode 100644 index 000000000000..355072ceb97c --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UsedLocalVariables.java @@ -0,0 +1,9 @@ +interface I { + void m(int i); +} +class B { + { + int a = 0; + I i = i1 -> System.out.println(i1 + a); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/functional/ExtractToMethodReferenceTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/functional/ExtractToMethodReferenceTest.java new file mode 100644 index 000000000000..0fc88338c1f4 --- /dev/null +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/functional/ExtractToMethodReferenceTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2017 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.siyeh.ipp.functional; + +import com.siyeh.IntentionPowerPackBundle; +import com.siyeh.ipp.IPPTestCase; + +public class ExtractToMethodReferenceTest extends IPPTestCase { + + public void testUnusedParameterToConfirmSignature() throws Exception { + doTest(); + } + + public void testOverloadedMethodSameName() throws Exception { + doTest(); + } + + public void testSameSignatureMethodExists() throws Exception { + doTest(); + } + + public void testUnableToCreateStatic() throws Exception { + doTest(); + } + + public void testRequiredTypeParameter() throws Exception { + doTest(); + } + + public void testConvertableToMethodReference() throws Exception { + assertIntentionNotAvailable(); + } + + public void testUsedLocalVariables() throws Exception { + assertIntentionNotAvailable(); + } + + @Override + protected String getIntentionName() { + return IntentionPowerPackBundle.message("extract.to.method.reference.intention.name"); + } + + @Override + protected String getRelativePath() { + return "functional/extractToMethodReference"; + } +} + From ee1712af7e0d78f2d9c8f2f05e5a7196fedd5f6f Mon Sep 17 00:00:00 2001 From: Ivan Bessonov Date: Fri, 7 Apr 2017 11:42:08 +0300 Subject: [PATCH 025/111] maven - fix of bombed ReimportingTest#testSettingTargetLevel test --- .../jetbrains/idea/maven/importing/ReimportingTest.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/ReimportingTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/ReimportingTest.java index f9c1bf732ca8..c086447beb7d 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/ReimportingTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/ReimportingTest.java @@ -16,7 +16,6 @@ package org.jetbrains.idea.maven.importing; import com.intellij.compiler.CompilerConfiguration; -import com.intellij.idea.Bombed; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.Module; @@ -29,7 +28,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import org.jetbrains.idea.maven.MavenImportingTestCase; -import java.util.Calendar; import java.util.concurrent.atomic.AtomicInteger; import static com.intellij.openapi.module.EffectiveLanguageLevelUtil.getEffectiveLanguageLevel; @@ -258,10 +256,9 @@ public class ReimportingTest extends MavenImportingTestCase { } - @Bombed(user = "Vladislav.Soroka", year=2020, month = Calendar.APRIL, day = 1, description = "temporary disabled") public void testSettingTargetLevel() throws Exception { createModulePom("m1", "test" + - "project" + + "m1" + "1"); importProject(); assertEquals("1.5", CompilerConfiguration.getInstance(myProject).getBytecodeTargetLevel(getModule("m1"))); @@ -301,7 +298,7 @@ public class ReimportingTest extends MavenImportingTestCase { // after configuration/target element delete in maven-compiler-plugin CompilerConfiguration#getBytecodeTargetLevel should be also updated createModulePom("m1", "test" + - "project" + + "m1" + "1"); importProject(); assertEquals("1.5", CompilerConfiguration.getInstance(myProject).getBytecodeTargetLevel(getModule("m1"))); From e640c100837fab39999c7e2d2833d7a07cb64b72 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 7 Apr 2017 11:24:04 +0200 Subject: [PATCH 026/111] IG: ignore casting class types to primitive (IDEA-170332) --- .../UnnecessaryExplicitNumericCastInspection.java | 3 ++- .../UnnecessaryExplicitNumericCast.java | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java index 14c0ad240403..7686bf6bb8de 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java @@ -121,6 +121,7 @@ public class UnnecessaryExplicitNumericCastInspection extends BaseInspection { } final PsiType operandType = operand.getType(); if (castType.equals(operandType) || isPrimitiveNumericCastNecessary(expression)) { + // equal types is caught by "Redundant type cast" inspection return; } final PsiTypeElement typeElement = expression.getCastType(); @@ -140,7 +141,7 @@ public class UnnecessaryExplicitNumericCastInspection extends BaseInspection { return true; } final PsiType operandType = operand.getType(); - if (operandType == null) { + if (!(operandType instanceof PsiPrimitiveType)) { return true; } PsiElement parent = expression.getParent(); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java index f055a845e11a..762768495d39 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java @@ -88,3 +88,17 @@ enum Numeric { Numeric(byte b) {} } +class S { + + static void doSomething() { + // V --- this cast is reported as unnecessary + if ( (int) whatever() < 0 ) { + } + } + + @SuppressWarnings("unchecked") + private static T whatever() { + return (T) (Object) 0; + } + +} \ No newline at end of file From 2a253bb865cd726542d9608dfe2d933a14abed3c Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Apr 2017 16:00:01 +0100 Subject: [PATCH 027/111] Remove unnecessary invokeAndWait It was introduced in 770b62a to collect changes under a modal progress, but the sense was lost after changes in 9b28336. --- .../git4idea/cherrypick/GitCherryPicker.java | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/plugins/git4idea/src/git4idea/cherrypick/GitCherryPicker.java b/plugins/git4idea/src/git4idea/cherrypick/GitCherryPicker.java index 8e59985674cd..871fe2bc44df 100644 --- a/plugins/git4idea/src/git4idea/cherrypick/GitCherryPicker.java +++ b/plugins/git4idea/src/git4idea/cherrypick/GitCherryPicker.java @@ -262,22 +262,17 @@ public class GitCherryPicker extends VcsCherryPicker { @NotNull final String commitMessage) { final CountDownLatch waiter = new CountDownLatch(1); final AtomicReference changeList = new AtomicReference<>(); - ApplicationManager.getApplication().invokeAndWait(new Runnable() { - @Override - public void run() { - myChangeListManager.invokeAfterUpdate(new Runnable() { - public void run() { - changeList.set(createChangeListIfThereAreChanges(commit, commitMessage)); - waiter.countDown(); - } - }, InvokeAfterUpdateMode.SILENT_CALLBACK_POOLED, "Cherry-pick", - new Consumer() { - public void consume(VcsDirtyScopeManager vcsDirtyScopeManager) { - vcsDirtyScopeManager.filePathsDirty(paths, null); - } - }, ModalityState.NON_MODAL); - } - }, ModalityState.NON_MODAL); + myChangeListManager.invokeAfterUpdate(new Runnable() { + public void run() { + changeList.set(createChangeListIfThereAreChanges(commit, commitMessage)); + waiter.countDown(); + } + }, InvokeAfterUpdateMode.SILENT_CALLBACK_POOLED, "Cherry-pick", + new Consumer() { + public void consume(VcsDirtyScopeManager vcsDirtyScopeManager) { + vcsDirtyScopeManager.filePathsDirty(paths, null); + } + }, ModalityState.NON_MODAL); try { boolean success = waiter.await(100, TimeUnit.SECONDS); if (!success) { From 22e5cfa1f5126f64bc39d691ef9539739b0c4937 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Apr 2017 22:10:13 +0100 Subject: [PATCH 028/111] Lambdify & simplify --- .../git4idea/cherrypick/GitCherryPicker.java | 97 +++++++------------ 1 file changed, 34 insertions(+), 63 deletions(-) diff --git a/plugins/git4idea/src/git4idea/cherrypick/GitCherryPicker.java b/plugins/git4idea/src/git4idea/cherrypick/GitCherryPicker.java index 871fe2bc44df..03e95a51f648 100644 --- a/plugins/git4idea/src/git4idea/cherrypick/GitCherryPicker.java +++ b/plugins/git4idea/src/git4idea/cherrypick/GitCherryPicker.java @@ -24,7 +24,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.AbstractVcsHelper; import com.intellij.openapi.vcs.FilePath; @@ -37,8 +37,6 @@ import com.intellij.openapi.vcs.update.RefreshVFsSynchronously; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; -import com.intellij.util.Consumer; -import com.intellij.util.Function; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.vcs.log.Hash; @@ -118,17 +116,9 @@ public class GitCherryPicker extends VcsCherryPicker { @NotNull private static String toString(@NotNull final Map> commitsInRoots) { - return StringUtil.join(commitsInRoots.keySet(), new Function() { - @Override - public String fun(@NotNull GitRepository repository) { - String commits = StringUtil.join(commitsInRoots.get(repository), new Function() { - @Override - public String fun(VcsFullCommitDetails details) { - return details.getId().asString(); - } - }, ", "); - return getShortRepositoryName(repository) + ": [" + commits + "]"; - } + return StringUtil.join(commitsInRoots.keySet(), repository -> { + String commits = StringUtil.join(commitsInRoots.get(repository), details -> details.getId().asString(), ", "); + return getShortRepositoryName(repository) + ": [" + commits + "]"; }, "; "); } @@ -260,19 +250,13 @@ public class GitCherryPicker extends VcsCherryPicker { @Nullable private LocalChangeList createChangeListAfterUpdate(@NotNull final VcsFullCommitDetails commit, @NotNull final Collection paths, @NotNull final String commitMessage) { - final CountDownLatch waiter = new CountDownLatch(1); - final AtomicReference changeList = new AtomicReference<>(); - myChangeListManager.invokeAfterUpdate(new Runnable() { - public void run() { - changeList.set(createChangeListIfThereAreChanges(commit, commitMessage)); - waiter.countDown(); - } - }, InvokeAfterUpdateMode.SILENT_CALLBACK_POOLED, "Cherry-pick", - new Consumer() { - public void consume(VcsDirtyScopeManager vcsDirtyScopeManager) { - vcsDirtyScopeManager.filePathsDirty(paths, null); - } - }, ModalityState.NON_MODAL); + CountDownLatch waiter = new CountDownLatch(1); + Ref changeList = Ref.create(); + myChangeListManager.invokeAfterUpdate(() -> { + changeList.set(createChangeListIfThereAreChanges(commit, commitMessage)); + waiter.countDown(); + }, InvokeAfterUpdateMode.SILENT_CALLBACK_POOLED, "Cherry-pick", + vcsDirtyScopeManager -> vcsDirtyScopeManager.filePathsDirty(paths, null), ModalityState.NON_MODAL); try { boolean success = waiter.await(100, TimeUnit.SECONDS); if (!success) { @@ -296,37 +280,34 @@ public class GitCherryPicker extends VcsCherryPicker { @NotNull final LocalChangeList changeList, @NotNull final String commitMessage) { final AtomicBoolean commitSucceeded = new AtomicBoolean(); final Semaphore sem = new Semaphore(0); - ApplicationManager.getApplication().invokeAndWait(new Runnable() { - @Override - public void run() { - try { - cancelCherryPick(repository); - Collection changes = commit.getCommit().getChanges(); - boolean commitNotCancelled = AbstractVcsHelper.getInstance(myProject).commitChanges(changes, changeList, commitMessage, - new CommitResultHandler() { - @Override - public void onSuccess(@NotNull String commitMessage) { - commit.setActualSubject(commitMessage); - commitSucceeded.set(true); - sem.release(); - } + ApplicationManager.getApplication().invokeAndWait(() -> { + try { + cancelCherryPick(repository); + Collection changes = commit.getCommit().getChanges(); + boolean commitNotCancelled = AbstractVcsHelper.getInstance(myProject).commitChanges(changes, changeList, commitMessage, + new CommitResultHandler() { + @Override + public void onSuccess(@NotNull String commitMessage1) { + commit.setActualSubject(commitMessage1); + commitSucceeded.set(true); + sem.release(); + } - @Override - public void onFailure() { - commitSucceeded.set(false); - sem.release(); - } - }); - - if (!commitNotCancelled) { + @Override + public void onFailure() { commitSucceeded.set(false); sem.release(); } - } catch (Throwable t) { - LOG.error(t); + }); + + if (!commitNotCancelled) { commitSucceeded.set(false); sem.release(); } + } catch (Throwable t) { + LOG.error(t); + commitSucceeded.set(false); + sem.release(); } }, ModalityState.NON_MODAL); @@ -412,12 +393,7 @@ public class GitCherryPicker extends VcsCherryPicker { @NotNull private static String formAlreadyPickedDescription(@NotNull List alreadyPicked, boolean but) { - String hashes = StringUtil.join(alreadyPicked, new Function() { - @Override - public String fun(GitCommitWrapper commit) { - return commit.getCommit().getId().toShortString(); - } - }, ", "); + String hashes = StringUtil.join(alreadyPicked, commit -> commit.getCommit().getId().toShortString(), ", "); if (but) { String wasnt = alreadyPicked.size() == 1 ? "wasn't" : "weren't"; String it = alreadyPicked.size() == 1 ? "it" : "them"; @@ -467,12 +443,7 @@ public class GitCherryPicker extends VcsCherryPicker { private boolean noChangesAfterCherryPick(@NotNull Collection originalChanges) { final Collection allChanges = myChangeListManager.getAllChanges(); - return !ContainerUtil.exists(originalChanges, new Condition() { - @Override - public boolean value(Change change) { - return allChanges.contains(change); - } - }); + return !ContainerUtil.exists(originalChanges, allChanges::contains); } @Nullable From f455d69096aebd101e2c7a945c2dc6b41e6baef1 Mon Sep 17 00:00:00 2001 From: Anton Tarasov Date: Fri, 7 Apr 2017 12:57:32 +0300 Subject: [PATCH 029/111] IDEA-170099 [followup] let Swing text components dynamically scale HTML text on user scale factor change --- platform/util/src/com/intellij/util/ui/UIUtil.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index 79ea03cd5d25..cc5676f290c8 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -2528,6 +2528,8 @@ public class UIUtil { public JBHtmlEditorKit(boolean noGapsBetweenParagraphs) { style.addStyleSheet(isUnderDarcula() ? (StyleSheet)UIManager.getDefaults().get("StyledEditorKit.JBDefaultStyle") : DEFAULT_HTML_KIT_CSS); + style.addRule("code { font-size: 90%; }"); // small by Swing's default, make it b/w small and medium + style.addRule("small { font-size: small; }"); // x-small by Swing's default if (noGapsBetweenParagraphs) style.addRule("p { margin-top: 0; }"); } From 73329cf8744f71130caedc3029ba19e5895b0bfa Mon Sep 17 00:00:00 2001 From: Alexander Lobas Date: Fri, 7 Apr 2017 13:01:54 +0300 Subject: [PATCH 030/111] Move swing dialog logic from write action --- .../openapi/application/ex/ApplicationUtil.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java index 20ef2f259b8c..2e47447c8a20 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java +++ b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.application.ex; +import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; @@ -76,6 +77,16 @@ public class ApplicationUtil { } } + public static void showDialogAfterWriteAction(@NotNull Runnable runnable) { + Application application = ApplicationManager.getApplication(); + if (application.isWriteAccessAllowed()) { + application.invokeLater(runnable); + } + else { + runnable.run(); + } + } + public static class CannotRunReadActionException extends ProcessCanceledException { } } \ No newline at end of file From ef35d35ff9187c78a127907cf601971bcb19d1c7 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 7 Apr 2017 12:24:19 +0200 Subject: [PATCH 031/111] fix building JDK 9 annotation type with @Target(ElementType.MODULE) --- .../jps/builders/java/dependencyView/ElemType.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ElemType.java b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ElemType.java index 3d311b18ee3a..6e4092f3cfbb 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ElemType.java +++ b/jps/jps-builders/src/org/jetbrains/jps/builders/java/dependencyView/ElemType.java @@ -52,5 +52,12 @@ public enum ElemType { * * @since 1.8 */ - TYPE_USE + TYPE_USE, + + /** + * Module declaration. + * + * @since 9 + */ + MODULE } From b68a4734b971472bce94aa1b8a084a72bb43cf25 Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Fri, 7 Apr 2017 13:28:59 +0300 Subject: [PATCH 032/111] -Didea.ui.debug.mode=true to switch ON at startup both 'UI Inspector' and 'Focus Debugger' Signed-off-by: Vassiliy.Kudryashov --- .../com/intellij/internal/focus/FocusDebuggerAction.java | 2 +- .../com/intellij/internal/inspector/UiInspectorAction.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/internal/focus/FocusDebuggerAction.java b/platform/platform-impl/src/com/intellij/internal/focus/FocusDebuggerAction.java index 46935ae0ea95..22490c63f831 100644 --- a/platform/platform-impl/src/com/intellij/internal/focus/FocusDebuggerAction.java +++ b/platform/platform-impl/src/com/intellij/internal/focus/FocusDebuggerAction.java @@ -37,7 +37,7 @@ public class FocusDebuggerAction extends AnAction implements DumbAware { private FocusDrawer myFocusDrawer; public FocusDebuggerAction() { - if (Boolean.getBoolean("focus.debug")) { + if (Boolean.getBoolean("idea.ui.debug.mode")) { ApplicationManager.getApplication().invokeLater(() -> actionPerformed(null)); } } diff --git a/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java b/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java index b8fd3d2140f3..b2642d40a260 100644 --- a/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java +++ b/platform/platform-impl/src/com/intellij/internal/inspector/UiInspectorAction.java @@ -24,6 +24,7 @@ import com.intellij.notification.Notifications; import com.intellij.notification.NotificationsManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.roots.ui.configuration.actions.IconWithTextAction; import com.intellij.openapi.ui.DialogWrapper; @@ -80,6 +81,12 @@ public class UiInspectorAction extends ToggleAction implements DumbAware { private UiInspector myInspector; + public UiInspectorAction() { + if (Boolean.getBoolean("idea.ui.debug.mode")) { + ApplicationManager.getApplication().invokeLater(() -> setSelected(null, true)); + } + } + @Override public boolean isSelected(AnActionEvent e) { return myInspector != null; From af675743e343a54d40543d46f56a2841a8c3feef Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 7 Apr 2017 11:08:41 +0200 Subject: [PATCH 033/111] intention to extract lambda body to method and convert to method reference: avoid overhead caused by extract method processor --- .../extractMethod/ExtractMethodProcessor.java | 65 +++--- .../ExtractToMethodReferenceIntention.java | 218 +++++++----------- .../FieldsUsedInsideLambda.java | 11 + .../FieldsUsedInsideLambda_after.java | 14 ++ .../NonDenotableParameterTypes.java | 9 + .../UnableToCreateStatic_after.java | 4 +- ...usedParameterToConfirmSignature_after.java | 8 +- .../ExtractToMethodReferenceTest.java | 16 ++ 8 files changed, 177 insertions(+), 168 deletions(-) create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/FieldsUsedInsideLambda.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/FieldsUsedInsideLambda_after.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/NonDenotableParameterTypes.java diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java index 483056038191..302bd6c5f96b 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -1616,39 +1616,7 @@ public class ExtractMethodProcessor implements MatchProvider { throws PrepareFailedException { myStatic = shouldBeStatic(); final Set fields = new LinkedHashSet<>(); - if (!PsiUtil.isLocalOrAnonymousClass(myTargetClass) && (myTargetClass.getContainingClass() == null || myTargetClass.hasModifierProperty(PsiModifier.STATIC))) { - boolean canBeStatic = true; - if (myTargetClass.isInterface()) { - final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(myCodeFragmentMember, PsiMethod.class, false); - canBeStatic = containingMethod == null || containingMethod.hasModifierProperty(PsiModifier.STATIC); - } - if (canBeStatic) { - ElementNeedsThis needsThis = new ElementNeedsThis(myTargetClass) { - @Override - protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { - if (classMember instanceof PsiField && !classMember.hasModifierProperty(PsiModifier.STATIC)) { - final PsiExpression expression = PsiTreeUtil.getParentOfType(classMemberReference, PsiExpression.class, false); - if (expression == null || !PsiUtil.isAccessedForWriting(expression)) { - fields.add((PsiField)classMember); - return; - } - } - super.visitClassMemberReferenceElement(classMember, classMemberReference); - } - }; - for (int i = 0; i < myElements.length && !needsThis.usesMembers(); i++) { - PsiElement element = myElements[i]; - element.accept(needsThis); - } - myCanBeStatic = !needsThis.usesMembers(); - } - else { - myCanBeStatic = false; - } - } - else { - myCanBeStatic = false; - } + myCanBeStatic = canBeStatic(myTargetClass, myCodeFragmentMember, myElements, fields); myInputVariables = new InputVariables(inputVariables, myProject, new LocalSearchScope(myElements), isFoldingApplicable()); myInputVariables.setUsedInstanceFields(fields); @@ -1665,6 +1633,37 @@ public class ExtractMethodProcessor implements MatchProvider { return true; } + public static boolean canBeStatic(final PsiClass targetClass, final PsiElement place, final PsiElement[] elements, Set usedFields) { + if (!PsiUtil.isLocalOrAnonymousClass(targetClass) && (targetClass.getContainingClass() == null || targetClass.hasModifierProperty(PsiModifier.STATIC))) { + boolean canBeStatic = true; + if (targetClass.isInterface()) { + final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(place, PsiMethod.class, false); + canBeStatic = containingMethod == null || containingMethod.hasModifierProperty(PsiModifier.STATIC); + } + if (canBeStatic) { + ElementNeedsThis needsThis = new ElementNeedsThis(targetClass) { + @Override + protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) { + if (classMember instanceof PsiField && !classMember.hasModifierProperty(PsiModifier.STATIC)) { + final PsiExpression expression = PsiTreeUtil.getParentOfType(classMemberReference, PsiExpression.class, false); + if (expression == null || !PsiUtil.isAccessedForWriting(expression)) { + usedFields.add((PsiField)classMember); + return; + } + } + super.visitClassMemberReferenceElement(classMember, classMemberReference); + } + }; + for (int i = 0; i < elements.length && !needsThis.usesMembers(); i++) { + PsiElement element = elements[i]; + element.accept(needsThis); + } + return !needsThis.usesMembers(); + } + } + return false; + } + protected boolean isFoldingApplicable() { return true; } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/functional/ExtractToMethodReferenceIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/functional/ExtractToMethodReferenceIntention.java index d81abab94969..065bfd5899af 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/functional/ExtractToMethodReferenceIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/functional/ExtractToMethodReferenceIntention.java @@ -18,33 +18,35 @@ package com.siyeh.ipp.functional; import com.intellij.codeInsight.CodeInsightUtilCore; import com.intellij.codeInsight.intention.BaseElementAtCaretIntentionAction; import com.intellij.codeInspection.LambdaCanBeMethodReferenceInspection; -import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pass; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.refactoring.extractMethod.AbstractExtractDialog; import com.intellij.refactoring.extractMethod.ControlFlowWrapper; import com.intellij.refactoring.extractMethod.ExtractMethodProcessor; import com.intellij.refactoring.extractMethod.PrepareFailedException; import com.intellij.refactoring.rename.RenamePsiElementProcessor; import com.intellij.refactoring.rename.inplace.MemberInplaceRenamer; -import com.intellij.refactoring.util.VariableData; +import com.intellij.refactoring.util.LambdaRefactoringUtil; +import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.ObjectUtils; import com.intellij.util.text.UniqueNameGenerator; import com.siyeh.IntentionPowerPackBundle; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Arrays; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; public class ExtractToMethodReferenceIntention extends BaseElementAtCaretIntentionAction { + private static final Logger LOG = Logger.getInstance(ExtractToMethodReferenceIntention.class); + @NotNull @Override public String getText() { @@ -63,8 +65,20 @@ public class ExtractToMethodReferenceIntention extends BaseElementAtCaretIntenti if (lambdaExpression != null) { PsiElement body = lambdaExpression.getBody(); if (body == null) return false; + + //is a valid lambda PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType(); - if (functionalInterfaceType == null) return false; + if (functionalInterfaceType == null || + LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType) == null || + !LambdaUtil.isLambdaFullyInferred(lambdaExpression, functionalInterfaceType)) { + return false; + } + + //can types be specified + if (LambdaRefactoringUtil.createLambdaParameterListWithFormalTypes(functionalInterfaceType, lambdaExpression, false) == null) { + return false; + } + PsiExpression asMethodReference = LambdaCanBeMethodReferenceInspection .canBeMethodReferenceProblem(body, lambdaExpression.getParameterList().getParameters(), functionalInterfaceType, null); if (asMethodReference != null) return false; @@ -84,139 +98,85 @@ public class ExtractToMethodReferenceIntention extends BaseElementAtCaretIntenti @Override public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException { - final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class, false); + PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class, false); if (lambdaExpression != null) { PsiElement body = lambdaExpression.getBody(); - if (body != null) { - PsiElement[] elements = body instanceof PsiCodeBlock ? ((PsiCodeBlock)body).getStatements() : new PsiElement[] {body}; - PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(lambdaExpression.getFunctionalInterfaceType()); - String initialMethodName = interfaceMethod != null ? interfaceMethod.getName() : "name"; - ExtractMethodProcessor methodProcessor = new ExtractMethodProcessor(project, editor, elements, null, getFamilyName(), null, null) { - @Override - public boolean showDialog() { - apply(new MyExtractMethodDialog(myTargetClass, lambdaExpression, myCanBeStatic, initialMethodName)); - return true; - } - }; - - try { - methodProcessor.prepare(); - } - catch (PrepareFailedException e) { - return; - } - methodProcessor.showDialog(); - WriteAction.run(() -> { - methodProcessor.doExtract(); - PsiExpression expression = LambdaCanBeMethodReferenceInspection.replaceLambdaWithMethodReference(lambdaExpression); - if (expression instanceof PsiMethodReferenceExpression) { - PsiMethod method = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(methodProcessor.getExtractedMethod()); - - PsiElement refElement = ((PsiMethodReferenceExpression)expression).getReferenceNameElement(); - PsiIdentifier nameIdentifier = method.getNameIdentifier(); - if (nameIdentifier == null) return; - - //try to navigate to reference name - editor.getCaretModel().moveToOffset(ObjectUtils.notNull(refElement, nameIdentifier).getTextOffset()); - - final RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(method); - if (!processor.isInplaceRenameSupported()) { - return; - } - List suggestedNames = new ArrayList<>(); - suggestedNames.add(method.getName()); - processor.substituteElementToRename(method, editor, new Pass() { - @Override - public void pass(PsiElement substitutedElement) { - final MemberInplaceRenamer renamer = new MemberInplaceRenamer(method, substitutedElement, editor); - final LinkedHashSet nameSuggestions = new LinkedHashSet<>(suggestedNames); - renamer.performInplaceRefactoring(nameSuggestions); - } - }); - } - }); + if (body instanceof PsiExpression) { + lambdaExpression = (PsiLambdaExpression)RefactoringUtil.expandExpressionLambdaToCodeBlock(body); + body = lambdaExpression.getBody(); } - } - } - @Nullable - @Override - public PsiElement getElementToMakeWritable(@NotNull PsiFile currentFile) { - return currentFile; - } + PsiClass targetClass = PsiTreeUtil.getParentOfType(lambdaExpression, PsiClass.class); + if (targetClass == null) return; + LOG.assertTrue(body instanceof PsiCodeBlock); + PsiElement[] elements = ((PsiCodeBlock)body).getStatements(); - @Override - public boolean startInWriteAction() { - return false; - } - - private static class MyExtractMethodDialog implements AbstractExtractDialog { - private final String myTargetMethodName; - private final boolean myCanBeStatic; - private final VariableData[] myVariableData; - - public MyExtractMethodDialog(@NotNull PsiClass targetClass, - PsiLambdaExpression lambdaExpression, - boolean canBeStatic, - String initialMethodName) { - myVariableData = Arrays.stream(lambdaExpression.getParameterList().getParameters()) - .map(parameter -> { - VariableData data = new VariableData(parameter); - data.passAsParameter = true; - data.name = parameter.getName(); - return data; - }) - .toArray(VariableData[]::new); - myCanBeStatic = canBeStatic; + HashSet usedFields = new HashSet<>(); + boolean canBeStatic = ExtractMethodProcessor.canBeStatic(targetClass, lambdaExpression, elements, usedFields) && usedFields.isEmpty(); PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(targetClass.getProject()); - String parameters = "(" + StringUtil.join(myVariableData, data -> data.type.getCanonicalText() + " " + data.name, ", ") + "){}"; - myTargetMethodName = UniqueNameGenerator.generateUniqueName(initialMethodName, - methodName -> { - String methodText = "private void " + methodName + parameters; - PsiMethod patternMethod = elementFactory.createMethodFromText(methodText, lambdaExpression); - return targetClass.findMethodBySignature(patternMethod, true) == null; - }); + PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType(); + String parameters = LambdaRefactoringUtil.createLambdaParameterListWithFormalTypes(functionalInterfaceType, lambdaExpression, false) + "{}"; + String targetMethodName = getUniqueMethodName(targetClass, elementFactory, functionalInterfaceType, parameters); + + PsiType returnType = LambdaUtil.getFunctionalInterfaceReturnType(lambdaExpression); + LOG.assertTrue(returnType != null); + PsiMethod container = PsiTreeUtil.getParentOfType(lambdaExpression, PsiMethod.class); + PsiTypeParameterList typeParamsList = + container != null ? RefactoringUtil.createTypeParameterListWithUsedTypeParameters(container.getTypeParameterList(), elements) : null; + PsiMethod emptyMethod = elementFactory.createMethodFromText("private " + (canBeStatic ? "static " : "") + + (typeParamsList != null ? typeParamsList.getText() + " " : "") + + returnType.getCanonicalText() + " " + + targetMethodName + parameters, targetClass); + PsiCodeBlock targetMethodBody = emptyMethod.getBody(); + LOG.assertTrue(targetMethodBody != null); + targetMethodBody.addRange(elements[0], elements[elements.length - 1]); + + PsiMethod method = (PsiMethod)CodeStyleManager.getInstance(project).reformat(JavaCodeStyleManager.getInstance(project).shortenClassReferences(targetClass.add(emptyMethod))); + PsiMethodReferenceExpression methodReference = + (PsiMethodReferenceExpression)elementFactory.createExpressionFromText((canBeStatic ? targetClass.getName() : "this") + "::" + targetMethodName, lambdaExpression); + methodReference = (PsiMethodReferenceExpression)lambdaExpression.replace(methodReference); + + startInplaceRename(editor, method, methodReference); } + } - @Override - public String getChosenMethodName() { - return myTargetMethodName; + private static void startInplaceRename(Editor editor, PsiMethod method, PsiMethodReferenceExpression methodReference) { + PsiIdentifier nameIdentifier = method.getNameIdentifier(); + if (nameIdentifier == null) return; + nameIdentifier = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(nameIdentifier); + + //try to navigate to reference name + editor.getCaretModel().moveToOffset(ObjectUtils.notNull(methodReference.getReferenceNameElement(), nameIdentifier).getTextOffset()); + + final RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(method); + if (!processor.isInplaceRenameSupported()) { + return; } + List suggestedNames = new ArrayList<>(); + suggestedNames.add(method.getName()); + processor.substituteElementToRename(method, editor, new Pass() { + @Override + public void pass(PsiElement substitutedElement) { + final MemberInplaceRenamer renamer = new MemberInplaceRenamer(method, substitutedElement, editor); + final LinkedHashSet nameSuggestions = new LinkedHashSet<>(suggestedNames); + renamer.performInplaceRefactoring(nameSuggestions); + } + }); + } - @Override - public VariableData[] getChosenParameters() { - return myVariableData; - } - - @NotNull - @Override - public String getVisibility() { - return PsiModifier.PRIVATE; - } - - @Override - public boolean isMakeStatic() { - return myCanBeStatic; - } - - @Override - public boolean isChainedConstructor() { - return false; - } - - @Override - public PsiType getReturnType() { - return null; - } - - @Override - public void show() {} - - @Override - public boolean isOK() { - return true; - } + private static String getUniqueMethodName(PsiClass targetClass, + PsiElementFactory elementFactory, + PsiType functionalInterfaceType, + String parameters) { + PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType); + String initialMethodName = interfaceMethod != null ? interfaceMethod.getName() : "name"; + return UniqueNameGenerator.generateUniqueName(initialMethodName, + methodName -> { + String methodText = "private void " + methodName + parameters; + PsiMethod patternMethod = elementFactory.createMethodFromText(methodText, targetClass); + return targetClass.findMethodBySignature(patternMethod, true) == null; + }); } } diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/FieldsUsedInsideLambda.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/FieldsUsedInsideLambda.java new file mode 100644 index 000000000000..4a22446ca772 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/FieldsUsedInsideLambda.java @@ -0,0 +1,11 @@ +import java.util.List; + +class MyClass { + + + String myStr; + void f(List l){ + l.stream().filter(s -> s.startsWith(myStr)); + } + +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/FieldsUsedInsideLambda_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/FieldsUsedInsideLambda_after.java new file mode 100644 index 000000000000..550a31da1efd --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/FieldsUsedInsideLambda_after.java @@ -0,0 +1,14 @@ +import java.util.List; + +class MyClass { + + + String myStr; + void f(List l){ + l.stream().filter(this::test); + } + + private boolean test(String s) { + return s.startsWith(myStr); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/NonDenotableParameterTypes.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/NonDenotableParameterTypes.java new file mode 100644 index 000000000000..98bc62415f04 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/NonDenotableParameterTypes.java @@ -0,0 +1,9 @@ +import java.util.List; + +class MyClass { + + + void f(List l) { + l.stream().filter(s -> s.substring(1).length() > 0); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnableToCreateStatic_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnableToCreateStatic_after.java index 4f5accb0fa9a..11a1dec92912 100644 --- a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnableToCreateStatic_after.java +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnableToCreateStatic_after.java @@ -3,10 +3,10 @@ interface I { } class B { class X { + I i = this::m; + private void m(int i1) { System.out.println(""); } - - I i = this::m; } } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnusedParameterToConfirmSignature_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnusedParameterToConfirmSignature_after.java index 216cd22ca70b..936f7b97e356 100644 --- a/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnusedParameterToConfirmSignature_after.java +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/functional/extractToMethodReference/UnusedParameterToConfirmSignature_after.java @@ -2,11 +2,11 @@ interface I { void m(int i); } class B { + { + I i = B::m; + } + private static void m(int i1) { System.out.println(""); } - - { - I i = B::m; - } } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/functional/ExtractToMethodReferenceTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/functional/ExtractToMethodReferenceTest.java index 0fc88338c1f4..5be4b04af3bf 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/functional/ExtractToMethodReferenceTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/functional/ExtractToMethodReferenceTest.java @@ -15,8 +15,10 @@ */ package com.siyeh.ipp.functional; +import com.intellij.testFramework.LightProjectDescriptor; import com.siyeh.IntentionPowerPackBundle; import com.siyeh.ipp.IPPTestCase; +import org.jetbrains.annotations.NotNull; public class ExtractToMethodReferenceTest extends IPPTestCase { @@ -40,10 +42,18 @@ public class ExtractToMethodReferenceTest extends IPPTestCase { doTest(); } + public void testFieldsUsedInsideLambda() throws Exception { + doTest(); + } + public void testConvertableToMethodReference() throws Exception { assertIntentionNotAvailable(); } + public void testNonDenotableParameterTypes() throws Exception { + assertIntentionNotAvailable(); + } + public void testUsedLocalVariables() throws Exception { assertIntentionNotAvailable(); } @@ -57,5 +67,11 @@ public class ExtractToMethodReferenceTest extends IPPTestCase { protected String getRelativePath() { return "functional/extractToMethodReference"; } + + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return JAVA_8; + } } From 46a7dbfc0d2d9cefa502724a6895ff953885ec08 Mon Sep 17 00:00:00 2001 From: nik Date: Fri, 7 Apr 2017 13:54:40 +0300 Subject: [PATCH 034/111] devkit: don't highlight usages of Pair constructor if diamonds can be used new Pair<>(...) is shorter than Pair.create so it makes no sense to highlight usages of Pair constructor if language level is 1.7 or newer. --- .../src/inspections/internal/DontUseNewPairInspection.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/devkit/src/inspections/internal/DontUseNewPairInspection.java b/plugins/devkit/src/inspections/internal/DontUseNewPairInspection.java index df72ee90f79b..9f984b732dec 100644 --- a/plugins/devkit/src/inspections/internal/DontUseNewPairInspection.java +++ b/plugins/devkit/src/inspections/internal/DontUseNewPairInspection.java @@ -17,7 +17,9 @@ package org.jetbrains.idea.devkit.inspections.internal; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; +import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.devkit.inspections.DevKitInspectionBase; import org.jetbrains.idea.devkit.inspections.quickfix.ChangeToPairCreateQuickFix; @@ -41,7 +43,7 @@ public class DontUseNewPairInspection extends DevKitInspectionBase { && ((PsiClassType)type).rawType().equalsToText(PAIR_FQN) && params != null && expression.getArgumentList() != null - //&& !PsiUtil.getLanguageLevel(expression).isAtLeast(LanguageLevel.JDK_1_7) //diamonds + && !PsiUtil.getLanguageLevel(expression).isAtLeast(LanguageLevel.JDK_1_7) //diamonds ) { final PsiType[] types = ((PsiClassType)type).getParameters(); if (Arrays.equals(types, params.getExpressionTypes())) { From 9fececc695780c5e05ce9f3504b84487a66e6260 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 7 Apr 2017 14:32:33 +0300 Subject: [PATCH 035/111] allow to publish kotlin/java courses to stepik --- .../resources/fileTemplates/internal/task.html.ft | 0 .../resources/fileTemplates/internal/task.md.ft | 0 .../actions/CCCreateStudyItemActionBase.java | 4 ---- .../edu/coursecreator/actions/CCCreateTask.java | 7 ++----- .../edu/coursecreator/stepik/CCStepicConnector.java | 1 + .../src/com/jetbrains/edu/learning/core/EduNames.java | 1 - .../edu/learning/courseFormat/RemoteCourse.java | 2 +- .../edu/learning/courseFormat/tasks/Task.java | 7 ++++++- .../jetbrains/edu/learning/stepic/StepicWrappers.java | 8 ++++++-- .../edu/learning/PyEduPluginConfigurator.java | 10 +++++----- 10 files changed, 21 insertions(+), 19 deletions(-) rename python/{educational-python => educational-core}/resources/fileTemplates/internal/task.html.ft (100%) rename python/{educational-python => educational-core}/resources/fileTemplates/internal/task.md.ft (100%) diff --git a/python/educational-python/resources/fileTemplates/internal/task.html.ft b/python/educational-core/resources/fileTemplates/internal/task.html.ft similarity index 100% rename from python/educational-python/resources/fileTemplates/internal/task.html.ft rename to python/educational-core/resources/fileTemplates/internal/task.html.ft diff --git a/python/educational-python/resources/fileTemplates/internal/task.md.ft b/python/educational-core/resources/fileTemplates/internal/task.md.ft similarity index 100% rename from python/educational-python/resources/fileTemplates/internal/task.md.ft rename to python/educational-core/resources/fileTemplates/internal/task.md.ft diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java index bad3979442b0..732f6dd904d3 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateStudyItemActionBase.java @@ -47,7 +47,6 @@ public abstract class CCCreateStudyItemActionBase extends DumbAwareAction { createItem(view, project, directory, course); } - @Override public void update(@NotNull AnActionEvent event) { final Presentation presentation = event.getPresentation(); @@ -78,13 +77,11 @@ public abstract class CCCreateStudyItemActionBase extends DumbAwareAction { presentation.setEnabledAndVisible(true); } - @Nullable protected abstract PsiDirectory getParentDir(@NotNull final Project project, @NotNull final Course course, @NotNull final PsiDirectory directory); - @Nullable public PsiDirectory createItem(@Nullable final IdeView view, @NotNull final Project project, @NotNull final PsiDirectory sourceDirectory, @NotNull final Course course) { @@ -106,7 +103,6 @@ public abstract class CCCreateStudyItemActionBase extends DumbAwareAction { protected abstract void addItem(@NotNull final Course course, @NotNull final StudyItem item); - protected abstract Function getStudyOrderable(@NotNull final StudyItem item); protected abstract PsiDirectory createItemDir(@NotNull final Project project, @NotNull final StudyItem item, diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java index f64e54b4a123..892f93ba0399 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java @@ -25,9 +25,6 @@ public class CCCreateTask extends CCCreateStudyItemActionBase { super(EduNames.TASK_TITLED, TITLE, EducationalCoreIcons.Task); } - - - @Nullable @Override protected PsiDirectory getParentDir(@NotNull Project project, @NotNull Course course, @NotNull PsiDirectory directory) { @@ -58,8 +55,8 @@ public class CCCreateTask extends CCCreateStudyItemActionBase { @Override @Nullable protected PsiDirectory createItemDir(@NotNull final Project project, @NotNull final StudyItem item, - @Nullable final IdeView view, @NotNull final PsiDirectory parentDirectory, - @NotNull final Course course) { + @Nullable final IdeView view, @NotNull final PsiDirectory parentDirectory, + @NotNull final Course course) { EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(course.getLanguageById()); if (configurator != null) { return configurator.createTaskContent(project, (Task)item, view, parentDirectory, course); diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/stepik/CCStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/stepik/CCStepicConnector.java index c5ac73922cb9..3ce6f33d90cb 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/stepik/CCStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/stepik/CCStepicConnector.java @@ -108,6 +108,7 @@ public class CCStepicConnector { postedCourse.setLessons(course.getLessons(true)); postedCourse.setAuthors(course.getAuthors()); postedCourse.setCourseMode(CCUtils.COURSE_MODE); + postedCourse.setLanguage(course.getLanguageID()); final int sectionId = postModule(postedCourse.getId(), 1, String.valueOf(postedCourse.getName())); int position = 1; for (Lesson lesson : course.getLessons()) { diff --git a/python/educational-core/src/com/jetbrains/edu/learning/core/EduNames.java b/python/educational-core/src/com/jetbrains/edu/learning/core/EduNames.java index 29a0cc2c7470..c2c35a63b217 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/core/EduNames.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/core/EduNames.java @@ -35,7 +35,6 @@ public class EduNames { public static final String WINDOWS_POSTFIX = "_windows"; public static final String ANSWERS_POSTFIX = "_answers"; public static final String USER_TESTS = "userTests"; - public static final String TESTS_FILE = "tests.py"; public static final String TEST_HELPER = "test_helper.py"; public static final String COURSE_META_FILE = "course.json"; diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/RemoteCourse.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/RemoteCourse.java index 5ba3b62984c2..40bf6eb65643 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/RemoteCourse.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/RemoteCourse.java @@ -17,7 +17,7 @@ import java.util.List; public class RemoteCourse extends Course { //course type in format "pycharm " - @SerializedName("course_format") private String myType = "pycharm" + EduStepicConnector.CURRENT_VERSION + " Python"; + @SerializedName("course_format") private String myType = "pycharm" + EduStepicConnector.CURRENT_VERSION + " " + getLanguageID(); @SerializedName("is_idea_compatible") private boolean isCompatible = true; List sections; List instructors = new ArrayList<>(); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/Task.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/Task.java index e3561075e1bf..947b2532a4d7 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/Task.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/Task.java @@ -2,12 +2,14 @@ package com.jetbrains.edu.learning.courseFormat.tasks; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; +import com.intellij.lang.Language; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.xmlb.XmlSerializer; import com.intellij.util.xmlb.annotations.Transient; +import com.jetbrains.edu.learning.EduPluginConfigurator; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.*; import com.jetbrains.edu.learning.stepic.EduStepicConnector; @@ -167,9 +169,12 @@ public class Task implements StudyItem { @NotNull public String getTestsText(@NotNull final Project project) { + final Course course = getLesson().getCourse(); + final Language language = course.getLanguageById(); + final EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(language); final VirtualFile taskDir = getTaskDir(project); if (taskDir != null) { - final VirtualFile file = taskDir.findChild(EduNames.TESTS_FILE); + final VirtualFile file = taskDir.findChild(configurator.getTestFileName()); if (file == null) return ""; final Document document = FileDocumentManager.getInstance().getDocument(file); if (document != null) { diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java index 1690b383f063..e7d1eefcdd91 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java @@ -2,13 +2,14 @@ package com.jetbrains.edu.learning.stepic; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; +import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.edu.learning.EduPluginConfigurator; import com.jetbrains.edu.learning.StudyUtils; -import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; @@ -136,13 +137,16 @@ public class StepicWrappers { } private static List getTestFiles(@NotNull Task task, @NotNull Project project) { + final Course course = task.getLesson().getCourse(); + final Language language = course.getLanguageById(); + final EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(language); List testFiles = new ArrayList<>(); VirtualFile taskDir = task.getTaskDir(project); if (taskDir == null) { return testFiles; } if (!(task instanceof TaskWithSubtasks)) { - VirtualFile testFile = taskDir.findChild(EduNames.TESTS_FILE); + VirtualFile testFile = taskDir.findChild(configurator.getTestFileName()); testFiles.add(testFile); return testFiles; } diff --git a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyEduPluginConfigurator.java b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyEduPluginConfigurator.java index cfd453a0e8cc..3bbdd68f95a7 100644 --- a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyEduPluginConfigurator.java +++ b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyEduPluginConfigurator.java @@ -77,10 +77,10 @@ public class PyEduPluginConfigurator implements EduPluginConfigurator { @Override public boolean isTestFile(VirtualFile file) { String name = file.getName(); - if (EduNames.TESTS_FILE.equals(name)) { + if (TESTS_PY.equals(name)) { return true; } - return name.contains(FileUtil.getNameWithoutExtension(EduNames.TESTS_FILE)) && name.contains(EduNames.SUBTASK_MARKER); + return name.contains(FileUtil.getNameWithoutExtension(TESTS_PY)) && name.contains(EduNames.SUBTASK_MARKER); } @Override @@ -94,7 +94,7 @@ public class PyEduPluginConfigurator implements EduPluginConfigurator { ApplicationManager.getApplication().runWriteAction(() -> { try { PsiDirectory taskPsiDir = PsiManager.getInstance(project).findDirectory(taskDir); - FileTemplate testsTemplate = FileTemplateManager.getInstance(project).getInternalTemplate(EduNames.TESTS_FILE); + FileTemplate testsTemplate = FileTemplateManager.getInstance(project).getInternalTemplate(TESTS_PY); if (taskPsiDir == null || testsTemplate == null) { return; } @@ -108,10 +108,10 @@ public class PyEduPluginConfigurator implements EduPluginConfigurator { @NotNull public static String getSubtaskTestsFileName(int index) { - return index == 0 ? EduNames.TESTS_FILE : FileUtil.getNameWithoutExtension(EduNames.TESTS_FILE) + + return index == 0 ? TESTS_PY : FileUtil.getNameWithoutExtension(TESTS_PY) + EduNames.SUBTASK_MARKER + index + "." + - FileUtilRt.getExtension(EduNames.TESTS_FILE); + FileUtilRt.getExtension(TESTS_PY); } @NotNull From 39159d0496c6d42e854418a0c1c79ab31ccbeaff Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 7 Apr 2017 13:39:45 +0200 Subject: [PATCH 036/111] Fix UAST test failure on Windows agents --- .../test/org/jetbrains/uast/test/java/AbstractJavaUastTest.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/uast/uast-tests/test/org/jetbrains/uast/test/java/AbstractJavaUastTest.kt b/uast/uast-tests/test/org/jetbrains/uast/test/java/AbstractJavaUastTest.kt index 03573072efa5..44b336496c80 100644 --- a/uast/uast-tests/test/org/jetbrains/uast/test/java/AbstractJavaUastTest.kt +++ b/uast/uast-tests/test/org/jetbrains/uast/test/java/AbstractJavaUastTest.kt @@ -27,6 +27,8 @@ abstract class AbstractJavaUastTest : AbstractUastFixtureTest() { } override fun getVirtualFile(testName: String): VirtualFile { - return LocalFileSystem.getInstance().findFileByPath(File(TEST_JAVA_MODEL_DIR, testName).canonicalPath)!! + val localPath = File(TEST_JAVA_MODEL_DIR, testName).path + val vFile = LocalFileSystem.getInstance().findFileByPath(localPath) + return vFile ?: throw IllegalStateException("Couldn't find virtual file for $localPath") } } \ No newline at end of file From ae5d51b8def0c824f7534dba18bd344c47945b08 Mon Sep 17 00:00:00 2001 From: Alexander Zolotov Date: Fri, 7 Apr 2017 14:39:05 +0300 Subject: [PATCH 037/111] Remove unpackJdks.gant All usages on TeamCity were migrated to using `gradlew setupJdks` task --- build/scripts/unpackJdks.gant | 50 ----------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 build/scripts/unpackJdks.gant diff --git a/build/scripts/unpackJdks.gant b/build/scripts/unpackJdks.gant deleted file mode 100644 index d938fcc6b960..000000000000 --- a/build/scripts/unpackJdks.gant +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2000-2017 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. - */ -import org.apache.tools.ant.BuildException - -target(default: "Unpack JDKs") { - def workingDirectory = getDependenciesProjectDir() - def gradleScript = System.getProperty('os.name').toLowerCase().contains('windows') ? "gradlew.bat" : "gradlew" - def process = new ProcessBuilder("${workingDirectory.absolutePath}/$gradleScript", 'setupJdks', '--stacktrace', '--info') - .directory(workingDirectory) - .start() - process.consumeProcessOutputStream((OutputStream)System.out) - process.consumeProcessErrorStream((OutputStream)System.err) - process.waitFor() - if (process.exitValue() != 0) { - throw new BuildException("Cannot unpack JDK") - } -} - -private File getDependenciesProjectDir() { - String home = guessHome(this) - File community = new File(home, 'community') - return new File(community.exists() ? community : new File(home), "build/dependencies") -} - -static String guessHome(Script script) { - File home = new File(script["gant.file"].substring("file:".length())) - - while (home != null) { - if (home.isDirectory()) { - if (new File(home, ".idea").exists()) return home.getCanonicalPath() - } - - home = home.getParentFile() - } - - return null -} \ No newline at end of file From 46b5b7470cccce64a75f9f6aa99f5b8a88c8d4a9 Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Fri, 7 Apr 2017 14:42:07 +0300 Subject: [PATCH 038/111] Refactor addNextRecommendation: 1) Check nullity when getting lesson from editor 2) Pass lesson as parameter 3) Minor Do not set lesson in addAsNextTask method because it's already set in task init --- .../stepic/EduAdaptiveStepicConnector.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java index 3c0f635fce8f..755ea42119ec 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java @@ -283,7 +283,12 @@ public class EduAdaptiveStepicConnector { public static void addNextRecommendedTask(@NotNull Project project, @NotNull ProgressIndicator indicator, int reactionToPost) { final StudyEditor editor = StudyUtils.getSelectedStudyEditor(project); final Course course = StudyTaskManager.getInstance(project).getCourse(); - if (course == null || editor == null || editor.getTaskFile() == null || !(course instanceof RemoteCourse)) { + Task selectedTask = StudyUtils.getTaskFromSelectedEditor(project); + if (editor == null || editor.getTaskFile() == null || selectedTask == null || selectedTask.getLesson() == null || + !(course instanceof RemoteCourse)) { + LOG.warn("Course is in incorrect state"); + ApplicationManager.getApplication().invokeLater(() -> StudyUtils.showErrorPopupOnToolbar(project, + "Can't get next recommendation: course is broken")); return; } @@ -296,7 +301,7 @@ public class EduAdaptiveStepicConnector { return; } - final Lesson lesson = editor.getTaskFile().getTask().getLesson(); + final Lesson lesson = selectedTask.getLesson(); final boolean reactionPosted = postRecommendationReaction(String.valueOf(lesson.getId()), String.valueOf(user.getId()), reactionToPost); if (!reactionPosted) { LOG.warn("Recommendation reaction wasn't posted"); @@ -315,10 +320,10 @@ public class EduAdaptiveStepicConnector { task.initTask(lesson, false); boolean replaceCurrentTask = reactionToPost == TOO_HARD_RECOMMENDATION_REACTION || reactionToPost == TOO_BORING_RECOMMENDATION_REACTION; if (replaceCurrentTask) { - replaceCurrentTask(project, editor, task); + replaceCurrentTask(project, editor, task, lesson); } else { - addAsNextTask(project, editor, task); + addAsNextTask(project, task, lesson); } ApplicationManager.getApplication().invokeLater(() -> { @@ -328,11 +333,10 @@ public class EduAdaptiveStepicConnector { }); } - private static void addAsNextTask(@NotNull Project project, @NotNull StudyEditor editor, @NotNull Task task) { + private static void addAsNextTask(@NotNull Project project, @NotNull Task task, @NotNull Lesson lesson) { Course course = StudyTaskManager.getInstance(project).getCourse(); assert course != null; - final Lesson lesson = editor.getTaskFile().getTask().getLesson(); lesson.addTask(task); task.setIndex(lesson.getTaskList().size()); lesson.initLesson(course, true); @@ -357,14 +361,12 @@ public class EduAdaptiveStepicConnector { } } - private static void replaceCurrentTask(@NotNull Project project, @NotNull StudyEditor editor, @NotNull Task task) { + private static void replaceCurrentTask(@NotNull Project project, @NotNull StudyEditor editor, @NotNull Task task, @NotNull Lesson lesson) { Course course = StudyTaskManager.getInstance(project).getCourse(); assert course != null; - final Lesson lesson = editor.getTaskFile().getTask().getLesson(); int taskIndex = lesson.getTaskList().size(); - task.setLesson(lesson); task.setIndex(taskIndex); lesson.getTaskList().set(taskIndex - 1, task); From e1f423e1d47e4492d99c3120242d7ac8456cc084 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Fri, 7 Apr 2017 15:19:49 +0300 Subject: [PATCH 039/111] IDEA-171134 Extract as method object generates the same getters --- .../ExtractMethodObjectProcessor.java | 27 ++++++++++++----- .../SameFieldsWithPrefix.java | 10 +++++++ .../SameFieldsWithPrefix.java.after | 30 +++++++++++++++++++ ...ethodObjectWithMultipleExitPointsTest.java | 20 +++++++++++-- 4 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/SameFieldsWithPrefix.java create mode 100644 java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/SameFieldsWithPrefix.java.after diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java index c34722cafebd..651b4612ecac 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -61,6 +61,8 @@ import com.intellij.usageView.UsageViewUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.VisibilityUtil; +import com.intellij.util.text.UniqueNameGenerator; +import one.util.streamex.StreamEx; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -86,6 +88,7 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { private PsiClass myInnerClass; private boolean myChangeReturnType; private Runnable myCopyMethodToInner; + private final UniqueNameGenerator myFieldNameGenerator = new UniqueNameGenerator(); private static final Key GENERATED_RETURN = new Key<>("GENERATED_RETURN"); @@ -163,8 +166,9 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { } if (myExtractProcessor.generatesConditionalExit()) { - myInnerClass.add(myElementFactory.createField("myResult", PsiPrimitiveType.BOOLEAN)); - myInnerClass.add(myElementFactory.createMethodFromText("boolean is(){return myResult;}", myInnerClass)); + String resultName = uniqueFieldName(new String[]{"myResult"}); + myInnerClass.add(myElementFactory.createField(resultName, PsiPrimitiveType.BOOLEAN)); + myInnerClass.add(myElementFactory.createMethodFromText("boolean is(){return " + resultName + ";}", myInnerClass)); } final PsiParameter[] parameters = getMethod().getParameterList().getParameters(); @@ -635,7 +639,8 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { if (type instanceof PsiEllipsisType) type = ((PsiEllipsisType)type).toArrayType(); try { final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(getMethod().getProject()); - final String fieldName = styleManager.suggestVariableName(VariableKind.FIELD, styleManager.variableNameToPropertyName(parameterName, VariableKind.PARAMETER), null, type).names[0]; + String fieldName = uniqueFieldName(styleManager.suggestVariableName( + VariableKind.FIELD, styleManager.variableNameToPropertyName(parameterName, VariableKind.PARAMETER), null, type).names); PsiField field = myElementFactory.createField(fieldName, type); final PsiModifierList modifierList = field.getModifierList(); @@ -725,6 +730,15 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { return true; } + private String uniqueFieldName(String[] candidates) { + String name = StreamEx.of(candidates).findFirst(myFieldNameGenerator::isUnique).orElse(null); + if (name == null) { + name = myFieldNameGenerator.generateUniqueName(candidates[0]); + } + myFieldNameGenerator.addExistingName(name); + return name; + } + public class MyExtractMethodProcessor extends ExtractMethodProcessor { public MyExtractMethodProcessor(Project project, @@ -767,9 +781,8 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { for (int i = 0; i < myOutputVariables.length; i++) { PsiVariable variable = myOutputVariables[i]; if (!myInputVariables.contains(variable)) { //one field creation - final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject); - final String fieldName = - styleManager.suggestVariableName(VariableKind.FIELD, getPureName(variable), null, variable.getType()).names[0]; + String fieldName = uniqueFieldName(JavaCodeStyleManager.getInstance(myProject) + .suggestVariableName(VariableKind.FIELD, getPureName(variable), null, variable.getType()).names); try { myOutputFields[i] = myElementFactory.createField(fieldName, variable.getType()); } diff --git a/java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/SameFieldsWithPrefix.java b/java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/SameFieldsWithPrefix.java new file mode 100644 index 000000000000..77c9d80e712f --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/SameFieldsWithPrefix.java @@ -0,0 +1,10 @@ +public class SameFieldsWithPrefix { + public static void main(String[] args) { + int aValue = 100; + int bValue = 1000; + + IntStream.of(aValue, bValue).peek(x -> {}).sum(); + + System.out.println(aValue + bValue); + } +} diff --git a/java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/SameFieldsWithPrefix.java.after b/java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/SameFieldsWithPrefix.java.after new file mode 100644 index 000000000000..97c635b2db93 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/SameFieldsWithPrefix.java.after @@ -0,0 +1,30 @@ +public class SameFieldsWithPrefix { + public static void main(String[] args) { + Inner inner = new Inner().invoke(); + int aValue = inner.getValue(); + int bValue = inner.getBValue(); + + System.out.println(aValue + bValue); + } + + private static class Inner { + private int myValue; + private int myBValue; + + public int getValue() { + return myValue; + } + + public int getBValue() { + return myBValue; + } + + public Inner invoke() { + myValue = 100; + myBValue = 1000; + + IntStream.of(myValue, myBValue).peek(x -> {}).sum(); + return this; + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObjectWithMultipleExitPointsTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObjectWithMultipleExitPointsTest.java index 20f78f6e9b33..b2e56e5f756d 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObjectWithMultipleExitPointsTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObjectWithMultipleExitPointsTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,9 +22,10 @@ package com.intellij.refactoring; import com.intellij.JavaTestUtil; import com.intellij.codeInsight.CodeInsightUtil; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiExpression; +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.refactoring.extractMethodObject.ExtractMethodObjectHandler; import com.intellij.refactoring.extractMethodObject.ExtractMethodObjectProcessor; import org.jetbrains.annotations.NotNull; @@ -150,4 +151,19 @@ public class ExtractMethodObjectWithMultipleExitPointsTest extends LightRefactor public void testAssignReturnValueToForeachParameter() throws Exception { doTest(); } + + public void testSameFieldsWithPrefix() throws Exception { + final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); + String oldPrefix = settings.FIELD_NAME_PREFIX; + settings.FIELD_NAME_PREFIX = "my"; + boolean oldPrefer = settings.PREFER_LONGER_NAMES; + settings.PREFER_LONGER_NAMES = false; + try { + doTest(); + } + finally { + settings.FIELD_NAME_PREFIX = oldPrefix; + settings.PREFER_LONGER_NAMES = oldPrefer; + } + } } From e52aa9e7941f00b51f9c1b0584f11749383ef062 Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Fri, 7 Apr 2017 15:30:10 +0300 Subject: [PATCH 040/111] adding `asyncable` to jetbrains.dic --- spellchecker/src/com/intellij/spellchecker/jetbrains.dic | 1 + 1 file changed, 1 insertion(+) diff --git a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic index aed2d015aa6d..27bdd07e1223 100644 --- a/spellchecker/src/com/intellij/spellchecker/jetbrains.dic +++ b/spellchecker/src/com/intellij/spellchecker/jetbrains.dic @@ -20,6 +20,7 @@ arquillian asensitive aspectj async +asyncable atomikos attr attlist From be4d57af720ef036b0a284c817521bcff3d90dad Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Thu, 6 Apr 2017 21:09:56 +0300 Subject: [PATCH 041/111] Fix deadlock on importing with Remote Debug Server (PY-23568) --- python/helpers/pydev/pydevd.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index ee02bf6acb99..2c7eaaaa1cee 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -35,7 +35,7 @@ from _pydevd_bundle.pydevd_comm import CMD_SET_BREAK, CMD_SET_NEXT_STATEMENT, CM from _pydevd_bundle.pydevd_custom_frames import CustomFramesContainer, custom_frames_container_init from _pydevd_bundle.pydevd_frame_utils import add_exception_to_frame from _pydevd_bundle.pydevd_kill_all_pydevd_threads import kill_all_pydev_threads -from _pydevd_bundle.pydevd_trace_dispatch import trace_dispatch as _trace_dispatch +from _pydevd_bundle.pydevd_trace_dispatch import trace_dispatch as _trace_dispatch, global_cache_skips, global_cache_frame_skips from _pydevd_frame_eval.pydevd_frame_eval_main import frame_eval_func, stop_frame_eval, set_use_code_extra from _pydevd_bundle.pydevd_utils import save_main_module from pydevd_concurrency_analyser.pydevd_concurrency_logger import ThreadingLogger, AsyncioLogger, send_message, cur_time @@ -586,7 +586,6 @@ class PyDB: def consolidate_breakpoints(self, file, id_to_breakpoint, breakpoints): - from _pydevd_bundle.pydevd_trace_dispatch import global_cache_skips, global_cache_frame_skips break_dict = {} for breakpoint_id, pybreakpoint in dict_iter_items(id_to_breakpoint): break_dict[pybreakpoint.line] = pybreakpoint From c7b59642c98122855eaeb2f3200102a09728bc3d Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Fri, 7 Apr 2017 15:33:25 +0300 Subject: [PATCH 042/111] Disable frame evaluation for remote debug server (PY-23587) We do it in order to have ability to stop on the next line after the settrace() call --- python/helpers/pydev/pydevd.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index 2c7eaaaa1cee..62d907bf1876 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -76,6 +76,7 @@ connected = False bufferStdOutToServer = False bufferStdErrToServer = False remote = False +inside_fork = False file_system_encoding = getfilesystemencoding() @@ -1171,7 +1172,7 @@ def _locked_settrace( global bufferStdOutToServer global bufferStdErrToServer - if not connected : + if not connected: pydevd_vm_type.setup_type() if SetupHolder.setup is None: @@ -1219,6 +1220,11 @@ def _locked_settrace( while not debugger.ready_to_run: time.sleep(0.1) # busy wait until we receive run command + global inside_fork + if frame_eval_func is not None and not inside_fork: + # Disable frame evaluation for Remote Debug Server + debugger.frame_eval_func = None + # note that we do that through pydevd_tracing.SetTrace so that the tracing # is not warned to the user! pydevd_tracing.SetTrace(debugger.trace_dispatch, debugger.frame_eval_func) @@ -1358,6 +1364,8 @@ def settrace_forked(): if port is not None: global connected connected = False + global inside_fork + inside_fork = True custom_frames_container_init() From 21036c0ba1544f7060080c83e812dfcc078c2414 Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Fri, 7 Apr 2017 15:23:58 +0300 Subject: [PATCH 043/111] EDU-913 Weird course description Fix typo --- .../com/jetbrains/edu/learning/stepic/EduStepicConnector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java index fb0998541a16..a7ead47048fc 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java @@ -39,7 +39,7 @@ public class EduStepicConnector { //this prefix indicates that course can be opened by educational plugin public static final String PYCHARM_PREFIX = "pycharm"; private static final String ADAPTIVE_NOTE = - "\n\nInitially, the adaptive system may behave somewhat randomly, but the more problems you solve, the smarter it become!"; + "\n\nInitially, the adaptive system may behave somewhat randomly, but the more problems you solve, the smarter it becomes!"; private EduStepicConnector() { } From 44be97d396bee6ce1bb478efed4b96b9fa55cc0f Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 7 Apr 2017 15:45:32 +0300 Subject: [PATCH 044/111] actual parameter is the same value inspection: add option to ignore method by visibility --- .../SameParameterValueInspection.java | 23 ++- .../UnusedSymbolLocalInspection.java | 146 +++--------------- .../VisibilityModifierChooser.java | 143 +++++++++++++++++ 3 files changed, 187 insertions(+), 125 deletions(-) create mode 100644 java/java-impl/src/com/intellij/codeInspection/unusedSymbol/VisibilityModifierChooser.java diff --git a/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java b/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java index ed9b38668a05..0643e66efe0a 100644 --- a/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java @@ -18,9 +18,11 @@ package com.intellij.codeInspection.sameParameterValue; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.unusedSymbol.VisibilityModifierChooser; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.LabeledComponent; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; @@ -35,8 +37,12 @@ import com.intellij.refactoring.util.CommonRefactoringUtil; import com.intellij.refactoring.util.InlineUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.MultiMap; +import com.intellij.util.ui.JBUI; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import javax.swing.*; +import java.awt.*; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -45,7 +51,22 @@ import java.util.List; * @author max */ public class SameParameterValueInspection extends SameParameterValueInspectionBase { - private static final Logger LOG = Logger.getInstance("#" + SameParameterValueInspectionBase.class.getName()); + private static final Logger LOG = Logger.getInstance(SameParameterValueInspectionBase.class); + + @Nullable + @Override + public JComponent createOptionsPanel() { + LabeledComponent component = LabeledComponent.create(new VisibilityModifierChooser(() -> true, + highestModifier, + (newModifier) -> highestModifier = newModifier), + "Methods to report:", + BorderLayout.WEST); + + JPanel panel = new JPanel(new GridBagLayout()); + panel.add(component, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.NORTHEAST, JBUI.emptyInsets(), 0, 0)); + return panel; + } + protected LocalQuickFix createFix(String paramName, String value) { return new InlineParameterValueFix(paramName, value); diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspection.java index 83385f4687cb..f4d2557abaff 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspection.java @@ -16,37 +16,13 @@ package com.intellij.codeInspection.unusedSymbol; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.ui.popup.JBPopup; -import com.intellij.openapi.ui.popup.JBPopupAdapter; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.ui.popup.LightweightWindowEvent; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiModifier; -import com.intellij.ui.ClickListener; -import com.intellij.ui.UI; -import com.intellij.ui.UserActivityProviderComponent; -import com.intellij.ui.awt.RelativePoint; -import com.intellij.util.ArrayUtil; -import com.intellij.util.Consumer; -import com.intellij.util.Producer; -import com.intellij.util.VisibilityUtil; -import com.intellij.util.containers.HashSet; -import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.MouseEvent; -import java.util.Hashtable; -import java.util.Set; -import java.util.function.Supplier; /** * User: anna @@ -107,13 +83,7 @@ public class UnusedSymbolLocalInspection extends UnusedSymbolLocalInspectionBase myCheckParametersCheckBox.addActionListener(listener); myInnerClassesCheckBox.addActionListener(listener); myAccessors.addActionListener(listener); - - ((MyLabel)myClassVisibilityCb).setupVisibilityLabel(() -> myClassVisibility, modifier -> setClassVisibility(modifier), new String[]{PsiModifier.PACKAGE_LOCAL, PsiModifier.PUBLIC}); - ((MyLabel)myInnerClassVisibilityCb).setupVisibilityLabel(() -> myInnerClassVisibility, modifier -> setInnerClassVisibility(modifier)); - ((MyLabel)myFieldVisibilityCb).setupVisibilityLabel(() -> myFieldVisibility, modifier -> setFieldVisibility(modifier)); - ((MyLabel)myMethodVisibilityCb).setupVisibilityLabel(() -> myMethodVisibility, modifier -> setMethodVisibility(modifier)); - ((MyLabel)myMethodParameterVisibilityCb).setupVisibilityLabel(() -> myParameterVisibility, modifier -> setParameterVisibility(modifier)); - } + } private void updateEnableState() { UIUtil.setEnabled(myClassVisibilityCb, CLASS, true); @@ -129,11 +99,27 @@ public class UnusedSymbolLocalInspection extends UnusedSymbolLocalInspectionBase } private void createUIComponents() { - myClassVisibilityCb = new MyLabel(() -> CLASS); - myInnerClassVisibilityCb = new MyLabel(() -> INNER_CLASS); - myFieldVisibilityCb = new MyLabel(() -> FIELD); - myMethodVisibilityCb = new MyLabel(() -> METHOD); - myMethodParameterVisibilityCb = new MyLabel(() -> PARAMETER); + myClassVisibilityCb = new VisibilityModifierChooser(() -> CLASS, + myClassVisibility, + modifier -> setClassVisibility(modifier), + new String[]{PsiModifier.PACKAGE_LOCAL, PsiModifier.PUBLIC}); + + myInnerClassVisibilityCb = new VisibilityModifierChooser(() -> INNER_CLASS, + myInnerClassVisibility, + modifier -> setInnerClassVisibility(modifier)); + + myFieldVisibilityCb = new VisibilityModifierChooser(() -> FIELD, + myFieldVisibility, + modifier -> setFieldVisibility(modifier)); + + myMethodVisibilityCb = new VisibilityModifierChooser(() -> METHOD, + myMethodVisibility, + modifier -> setMethodVisibility(modifier)); + + myMethodParameterVisibilityCb = new VisibilityModifierChooser(() -> PARAMETER, + myParameterVisibility, + modifier -> setParameterVisibility(modifier)); + myAccessors = new JCheckBox() { @Override public void setEnabled(boolean b) { @@ -143,94 +129,6 @@ public class UnusedSymbolLocalInspection extends UnusedSymbolLocalInspectionBase } } - private static class MyLabel extends JLabel implements UserActivityProviderComponent { - - @PsiModifier.ModifierConstant private static final String[] MODIFIERS = - new String[]{PsiModifier.PRIVATE, PsiModifier.PACKAGE_LOCAL, PsiModifier.PROTECTED, PsiModifier.PUBLIC}; - private final Supplier myCanBeEnabled; - - private Set myListeners = new HashSet<>(); - - public MyLabel(Supplier canBeEnabled) { - myCanBeEnabled = canBeEnabled; - setIcon(AllIcons.General.Combo2); - setDisabledIcon(AllIcons.General.Combo2); - setIconTextGap(0); - setHorizontalTextPosition(SwingConstants.LEFT); - } - - private void fireStateChanged() { - for (ChangeListener listener : myListeners) { - listener.stateChanged(new ChangeEvent(this)); - } - } - - private static String getPresentableText(String modifier) { - return StringUtil.capitalize(VisibilityUtil.toPresentableText(modifier)); - } - - private void setupVisibilityLabel(Producer visibilityProducer, Consumer setter) { - setupVisibilityLabel(visibilityProducer, setter, MODIFIERS); - } - - private void setupVisibilityLabel(Producer visibilityProducer, Consumer setter, final String[] modifiers) { - setText(getPresentableText(visibilityProducer.produce())); - new ClickListener() { - @Override - public boolean onClick(@NotNull MouseEvent e, int clickCount) { - if (!isEnabled()) return true; - @SuppressWarnings("UseOfObsoleteCollectionType") - Hashtable sliderLabels = new Hashtable<>(); - for (int i = 0; i < modifiers.length; i++) { - sliderLabels.put(i + 1, new JLabel(getPresentableText(modifiers[i]))); - } - - JSlider slider = new JSlider(SwingConstants.VERTICAL, 1, modifiers.length, 1); - slider.addChangeListener(val -> { - final String modifier = modifiers[slider.getValue() - 1]; - setter.consume(modifier); - setText(getPresentableText(modifier)); - fireStateChanged(); - }); - slider.setLabelTable(sliderLabels); - slider.putClientProperty(UIUtil.JSLIDER_ISFILLED, Boolean.TRUE); - slider.setPreferredSize(JBUI.size(150, modifiers.length * 25)); - slider.setPaintLabels(true); - slider.setSnapToTicks(true); - slider.setValue(ArrayUtil.find(modifiers, visibilityProducer.produce()) + 1); - final JBPopup popup = JBPopupFactory.getInstance() - .createComponentPopupBuilder(slider, null) - .setTitle("Effective Visibility") - .setCancelOnClickOutside(true) - .setMovable(true) - .createPopup(); - popup.show(new RelativePoint(MyLabel.this, new Point(getWidth(), 0))); - return true; - } - }.installOn(this); - } - - @Override - public void setForeground(Color fg) { - super.setForeground(isEnabled() ? UI.getColor("link.foreground") : fg); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled && myCanBeEnabled.get()); - } - - @Override - public void addChangeListener(ChangeListener changeListener) { - myListeners.add(changeListener); - } - - @Override - public void removeChangeListener(ChangeListener changeListener) { - myListeners.remove(changeListener); - } - } - @Override @Nullable public JComponent createOptionsPanel() { diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/VisibilityModifierChooser.java b/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/VisibilityModifierChooser.java new file mode 100644 index 000000000000..b64097fe159a --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/VisibilityModifierChooser.java @@ -0,0 +1,143 @@ +/* + * Copyright 2000-2017 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.unusedSymbol; + +import com.intellij.icons.AllIcons; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiModifier; +import com.intellij.ui.ClickListener; +import com.intellij.ui.UI; +import com.intellij.ui.UserActivityProviderComponent; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.ArrayUtil; +import com.intellij.util.Consumer; +import com.intellij.util.VisibilityUtil; +import com.intellij.util.containers.HashSet; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import java.awt.*; +import java.awt.event.MouseEvent; +import java.util.Hashtable; +import java.util.Set; +import java.util.function.Supplier; + +public class VisibilityModifierChooser extends JLabel implements UserActivityProviderComponent { + + @PsiModifier.ModifierConstant private static final String[] MODIFIERS = + new String[]{PsiModifier.PRIVATE, PsiModifier.PACKAGE_LOCAL, PsiModifier.PROTECTED, PsiModifier.PUBLIC}; + private final Supplier myCanBeEnabled; + + private final Set myListeners = new HashSet<>(); + private String myCurrentModifier; + + public VisibilityModifierChooser(@NotNull Supplier canBeEnabled, + @NotNull String modifier, + @NotNull Consumer modifierChangedConsumer) { + this(canBeEnabled, modifier, modifierChangedConsumer, MODIFIERS); + } + + + @Override + public void setText(String text) { + super.setText(text); + } + + public VisibilityModifierChooser(@NotNull Supplier canBeEnabled, + @NotNull String modifier, + @NotNull Consumer modifierChangedConsumer, + @NotNull String[] modifiers) { + myCanBeEnabled = canBeEnabled; + setIcon(AllIcons.General.Combo2); + setDisabledIcon(AllIcons.General.Combo2); + setIconTextGap(0); + setHorizontalTextPosition(SwingConstants.LEFT); + myCurrentModifier = modifier; + setText(getPresentableText(myCurrentModifier)); + new ClickListener() { + @Override + public boolean onClick(@NotNull MouseEvent e, int clickCount) { + if (!isEnabled()) return true; + @SuppressWarnings("UseOfObsoleteCollectionType") + Hashtable sliderLabels = new Hashtable<>(); + for (int i = 0; i < modifiers.length; i++) { + sliderLabels.put(i + 1, new JLabel(getPresentableText(modifiers[i]))); + } + + JSlider slider = new JSlider(SwingConstants.VERTICAL, 1, modifiers.length, 1); + slider.addChangeListener(val -> { + final String modifier = modifiers[slider.getValue() - 1]; + if (myCurrentModifier != modifier) { + myCurrentModifier = modifier; + modifierChangedConsumer.consume(modifier); + setText(getPresentableText(modifier)); + fireStateChanged(); + } + }); + slider.setLabelTable(sliderLabels); + slider.putClientProperty(UIUtil.JSLIDER_ISFILLED, Boolean.TRUE); + slider.setPreferredSize(JBUI.size(150, modifiers.length * 25)); + slider.setPaintLabels(true); + slider.setSnapToTicks(true); + slider.setValue(ArrayUtil.find(modifiers, myCurrentModifier) + 1); + final JBPopup popup = JBPopupFactory.getInstance() + .createComponentPopupBuilder(slider, null) + .setTitle("Effective Visibility") + .setCancelOnClickOutside(true) + .setMovable(true) + .createPopup(); + popup.show(new RelativePoint(VisibilityModifierChooser.this, new Point(getWidth(), 0))); + return true; + } + }.installOn(this); + } + + private void fireStateChanged() { + for (ChangeListener listener : myListeners) { + listener.stateChanged(new ChangeEvent(this)); + } + } + + private static String getPresentableText(String modifier) { + return StringUtil.capitalize(VisibilityUtil.toPresentableText(modifier)); + } + + @Override + public void setForeground(Color fg) { + super.setForeground(isEnabled() ? UI.getColor("link.foreground") : fg); + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled && myCanBeEnabled.get()); + } + + @Override + public void addChangeListener(ChangeListener changeListener) { + myListeners.add(changeListener); + } + + @Override + public void removeChangeListener(ChangeListener changeListener) { + myListeners.remove(changeListener); + } +} From 9c26a6fae597f905031e92b85a78dfdd5fe88e92 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 7 Apr 2017 14:58:03 +0200 Subject: [PATCH 045/111] inference: ensure unchecked warning is passed to all call expressions inside method call args --- .../resolve/graphInference/InferenceSession.java | 10 +++++++--- .../constraints/ExpressionCompatibilityConstraint.java | 4 +--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index 64a4bddb7700..80074749c1ee 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -1146,9 +1146,7 @@ public class InferenceSession { } } - if (myContext != null) { - myContext.putUserData(ERASED, myErased); - } + setUncheckedInContext(); final Map map = substitutor.getSubstitutionMap(); for (PsiTypeParameter parameter : map.keySet()) { @@ -1169,6 +1167,12 @@ public class InferenceSession { } } + public void setUncheckedInContext() { + if (myContext != null) { + myContext.putUserData(ERASED, myErased); + } + } + private boolean initFreshVariables(PsiSubstitutor substitutor, List vars) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject()); PsiSubstitutor ySubstitutor = PsiSubstitutor.EMPTY; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index 918c07fda6b6..4a6ef5c74700 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -106,9 +106,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm if (callSession != session) { session.getInferenceSessionContainer().registerNestedSession(callSession); session.propagateVariables(callSession.getInferenceVariables(), callSession.getRestoreNameSubstitution()); -/* if (callSession.isErased()) { - session.setErased(); - }*/ + callSession.setUncheckedInContext(); } return true; } From 7f56e62e4f56f2755c27be0754f98f4c37c6d4f8 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 7 Apr 2017 16:08:49 +0300 Subject: [PATCH 046/111] actual parameter is the same value inspection: add option to ignore method by visibility Dmitry Batkovich 7/4/2017, 3:45 PM --- .../SameParameterValueInspectionBase.java | 22 +++++++++++++--- .../unusedSymbol/OptionsPanel.form | 26 +++++-------------- .../expected.xml | 4 +++ .../src/Test.java | 11 ++++++++ .../SameParameterValueLocalTest.java | 20 +++++++++++++- .../SameParameterValueTest.java | 26 +++++++++++++++++-- 6 files changed, 83 insertions(+), 26 deletions(-) create mode 100644 java/java-tests/testData/inspection/sameParameterValue/notReportedDueToHighVisibility/expected.xml create mode 100644 java/java-tests/testData/inspection/sameParameterValue/notReportedDueToHighVisibility/src/Test.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java index 7a0ade4c627a..fb12db8280f7 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java @@ -25,6 +25,8 @@ import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; import com.intellij.util.ObjectUtils; +import com.intellij.util.VisibilityUtil; +import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,6 +37,18 @@ import java.util.List; * @author max */ public class SameParameterValueInspectionBase extends GlobalJavaBatchInspectionTool { + @PsiModifier.ModifierConstant + private static final String DEFAULT_HIGHEST_MODIFIER = PsiModifier.PROTECTED; + @PsiModifier.ModifierConstant + public String highestModifier = DEFAULT_HIGHEST_MODIFIER; + + @Override + public void writeSettings(@NotNull Element node) { + if (highestModifier != DEFAULT_HIGHEST_MODIFIER) { + super.writeSettings(node); + } + } + @Override @Nullable public CommonProblemDescriptor[] checkElement(@NotNull RefEntity refEntity, @@ -46,9 +60,9 @@ public class SameParameterValueInspectionBase extends GlobalJavaBatchInspectionT if (refEntity instanceof RefMethod) { final RefMethod refMethod = (RefMethod)refEntity; - if (refMethod.hasSuperMethods()) return null; - - if (refMethod.isEntry()) return null; + if (refMethod.hasSuperMethods() || + VisibilityUtil.compare(refMethod.getAccessModifier(), highestModifier) < 0 || + refMethod.isEntry()) return null; RefParameter[] parameters = refMethod.getParameters(); for (RefParameter refParameter : parameters) { @@ -176,7 +190,7 @@ public class SameParameterValueInspectionBase extends GlobalJavaBatchInspectionT @Override public void visitMethod(PsiMethod method) { - if (method.isConstructor()) return; + if (method.isConstructor() || VisibilityUtil.compare(VisibilityUtil.getVisibilityModifier(method.getModifierList()), highestModifier) < 0) return; PsiParameter[] parameters = method.getParameterList().getParameters(); if (parameters.length == 0) return; diff --git a/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/OptionsPanel.form b/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/OptionsPanel.form index 5b3cac3661f2..ba373af3f2e4 100644 --- a/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/OptionsPanel.form +++ b/java/java-impl/src/com/intellij/codeInspection/unusedSymbol/OptionsPanel.form @@ -3,7 +3,7 @@ - + @@ -54,9 +54,7 @@ - - - + @@ -83,9 +81,7 @@ - - - + @@ -110,9 +106,7 @@ - - - + @@ -139,9 +133,7 @@ - - - + @@ -168,18 +160,14 @@ - - - + - - - + diff --git a/java/java-tests/testData/inspection/sameParameterValue/notReportedDueToHighVisibility/expected.xml b/java/java-tests/testData/inspection/sameParameterValue/notReportedDueToHighVisibility/expected.xml new file mode 100644 index 000000000000..bdafc52f107c --- /dev/null +++ b/java/java-tests/testData/inspection/sameParameterValue/notReportedDueToHighVisibility/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/sameParameterValue/notReportedDueToHighVisibility/src/Test.java b/java/java-tests/testData/inspection/sameParameterValue/notReportedDueToHighVisibility/src/Test.java new file mode 100644 index 000000000000..70af88aaeeee --- /dev/null +++ b/java/java-tests/testData/inspection/sameParameterValue/notReportedDueToHighVisibility/src/Test.java @@ -0,0 +1,11 @@ +public class Test { + void m() { + mmmmmmmmmm(false); + mmmmmmmmmm(false); + mmmmmmmmmm(false); + } + + public void mmmmmmmmmm(boolean t) { + + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueLocalTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueLocalTest.java index 682d54f93454..85595083d51e 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueLocalTest.java @@ -17,10 +17,18 @@ package com.intellij.codeInspection; import com.intellij.JavaTestUtil; import com.intellij.codeInspection.sameParameterValue.SameParameterValueInspection; +import com.intellij.psi.PsiModifier; import com.intellij.testFramework.InspectionTestCase; public class SameParameterValueLocalTest extends InspectionTestCase { - private LocalInspectionTool myTool = new SameParameterValueInspection().getSharedLocalInspectionTool(); + private final SameParameterValueInspection myGlobalTool = new SameParameterValueInspection(); + private LocalInspectionTool myTool = myGlobalTool.getSharedLocalInspectionTool(); + + @Override + public void setUp() throws Exception { + super.setUp(); + //myGlobalTool.highestModifier = PsiModifier.PUBLIC; + } @Override protected String getTestDataPath() { @@ -42,6 +50,16 @@ public class SameParameterValueLocalTest extends InspectionTestCase { } public void testMethodWithSuper() { + String previous = myGlobalTool.highestModifier; + myGlobalTool.highestModifier = PsiModifier.PUBLIC; + try { + doTest(getGlobalTestDir(), myTool); + } finally { + myGlobalTool.highestModifier = previous; + } + } + + public void testNotReportedDueToHighVisibility() { doTest(getGlobalTestDir(), myTool); } diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueTest.java index a21817d196e2..b77996f3b947 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/SameParameterValueTest.java @@ -2,11 +2,17 @@ package com.intellij.codeInspection; import com.intellij.JavaTestUtil; import com.intellij.codeInspection.sameParameterValue.SameParameterValueInspection; +import com.intellij.psi.PsiModifier; import com.intellij.testFramework.InspectionTestCase; public class SameParameterValueTest extends InspectionTestCase { private SameParameterValueInspection myTool = new SameParameterValueInspection(); + @Override + public void setUp() throws Exception { + super.setUp(); + } + @Override protected String getTestDataPath() { return JavaTestUtil.getJavaTestDataPath() + "/inspection"; @@ -27,7 +33,13 @@ public class SameParameterValueTest extends InspectionTestCase { } public void testWithoutDeadCode() { - doTest(getTestDir(), myTool, false, false); + String previous = myTool.highestModifier; + myTool.highestModifier = PsiModifier.PUBLIC; + try { + doTest(getTestDir(), myTool, false, false); + } finally { + myTool.highestModifier = previous; + } } public void testVarargs() { @@ -39,6 +51,16 @@ public class SameParameterValueTest extends InspectionTestCase { } public void testMethodWithSuper() { - doTest(getTestDir(), myTool, false, true); + String previous = myTool.highestModifier; + myTool.highestModifier = PsiModifier.PUBLIC; + try { + doTest(getTestDir(), myTool, false, true); + } finally { + myTool.highestModifier = previous; + } + } + + public void testNotReportedDueToHighVisibility() { + doTest(getTestDir(), myTool, false, false); } } From 710b8db17498d3734aedad013a09022f2ff6432a Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Fri, 7 Apr 2017 16:15:58 +0300 Subject: [PATCH 047/111] IDEA-171134 Extract as method object generates the same getters - correctly handle result field --- .../ExtractMethodObjectProcessor.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java index 651b4612ecac..4445064de890 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java @@ -89,6 +89,7 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { private boolean myChangeReturnType; private Runnable myCopyMethodToInner; private final UniqueNameGenerator myFieldNameGenerator = new UniqueNameGenerator(); + private String myResultFieldName = null; private static final Key GENERATED_RETURN = new Key<>("GENERATED_RETURN"); @@ -166,9 +167,9 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { } if (myExtractProcessor.generatesConditionalExit()) { - String resultName = uniqueFieldName(new String[]{"myResult"}); - myInnerClass.add(myElementFactory.createField(resultName, PsiPrimitiveType.BOOLEAN)); - myInnerClass.add(myElementFactory.createMethodFromText("boolean is(){return " + resultName + ";}", myInnerClass)); + myResultFieldName = uniqueFieldName(new String[]{"myResult"}); + myInnerClass.add(myElementFactory.createField(myResultFieldName, PsiType.BOOLEAN)); + myInnerClass.add(myElementFactory.createMethodFromText("boolean is(){return " + myResultFieldName + ";}", myInnerClass)); } final PsiParameter[] parameters = getMethod().getParameterList().getParameters(); @@ -289,7 +290,8 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { for (int i = 0; i < returnStatements.size() - 1; i++) { final PsiReturnStatement condition = returnStatements.get(i); final PsiElement container = condition.getParent(); - final PsiStatement resultStmt = myElementFactory.createStatementFromText("myResult = true;", container); + LOG.assertTrue(myResultFieldName != null); + final PsiStatement resultStmt = myElementFactory.createStatementFromText(myResultFieldName + " = true;", container); if (!RefactoringUtil.isLoopOrIf(container)) { container.addBefore(resultStmt, condition); } else { @@ -300,7 +302,8 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { LOG.assertTrue(!returnStatements.isEmpty()); final PsiReturnStatement returnStatement = returnStatements.get(returnStatements.size() - 1); final PsiElement container = returnStatement.getParent(); - final PsiStatement resultStmt = myElementFactory.createStatementFromText("myResult = false;", container); + LOG.assertTrue(myResultFieldName != null); + final PsiStatement resultStmt = myElementFactory.createStatementFromText(myResultFieldName + " = false;", container); if (!RefactoringUtil.isLoopOrIf(container)) { container.addBefore(resultStmt, returnStatement); } else { From 1d1a4bccdbe5664a49151e4d53afe591aba8a248 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Fri, 7 Apr 2017 16:24:06 +0300 Subject: [PATCH 048/111] actual parameter is the same value inspection: add option to ignore method by visibility (remove redundant writeSettings) --- .../SameParameterValueInspectionBase.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java index fb12db8280f7..153d4b35cca0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspectionBase.java @@ -26,7 +26,6 @@ import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.psi.*; import com.intellij.util.ObjectUtils; import com.intellij.util.VisibilityUtil; -import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -42,13 +41,6 @@ public class SameParameterValueInspectionBase extends GlobalJavaBatchInspectionT @PsiModifier.ModifierConstant public String highestModifier = DEFAULT_HIGHEST_MODIFIER; - @Override - public void writeSettings(@NotNull Element node) { - if (highestModifier != DEFAULT_HIGHEST_MODIFIER) { - super.writeSettings(node); - } - } - @Override @Nullable public CommonProblemDescriptor[] checkElement(@NotNull RefEntity refEntity, From 7ed158d543dde684085230b1126a6149cdd31bfb Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Fri, 7 Apr 2017 15:57:49 +0300 Subject: [PATCH 049/111] [git] avoid copying the whole git log output for parsing Git log output can be quite big, either we have a big list of commits or one big commit with many changed files (the former is not a problem, but the latter can be). In order to parse it GitLogParser is used, but unfortunately its methods required a String as an input, while git log output is stored in a StringBuilder. StringBuilder.toString method copies the contents instead of sharing it. This is unnecessary since parsing is done sequentially. So to avoid input copying GitLogParser now accepts CharSequences. --- .../src/git4idea/history/GitHistoryUtils.java | 4 +-- .../src/git4idea/history/GitLogParser.java | 31 ++++++++++--------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java index bb48d517a29b..178675830bec 100644 --- a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java +++ b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java @@ -514,7 +514,7 @@ public class GitHistoryUtils { Ref parseError = new Ref<>(); processHandlerOutputByLine(handler, builder -> { try { - GitLogRecord record = parser.parseOneRecord(builder.toString()); + GitLogRecord record = parser.parseOneRecord(builder); if (record != null) { recordConsumer.consume(record); } @@ -581,7 +581,7 @@ public class GitHistoryUtils { @NotNull Consumer refConsumer, @NotNull VcsLogObjectsFactory factory, @NotNull VirtualFile root) { - List gitLogRecords = parser.parse(record.toString()); + List gitLogRecords = parser.parse(record); return ContainerUtil.mapNotNull(gitLogRecords, gitLogRecord -> { if (gitLogRecord == null) { return null; diff --git a/plugins/git4idea/src/git4idea/history/GitLogParser.java b/plugins/git4idea/src/git4idea/history/GitLogParser.java index 388dc07aa08b..49476cd15e4f 100644 --- a/plugins/git4idea/src/git4idea/history/GitLogParser.java +++ b/plugins/git4idea/src/git4idea/history/GitLogParser.java @@ -40,13 +40,13 @@ import java.util.regex.Pattern; * 1. Pass options you want to have in the output to the constructor using the {@link GitLogOption} enum constants. * 2. Get the custom format pattern for 'git log' by calling {@link #getPretty()} * 3. Call the command and retrieve the output. - * 4. Parse the output via {@link #parse(String)} or {@link #parseOneRecord(String)} (if you want the output to be parsed line by line).

+ * 4. Parse the output via {@link #parse(CharSequence)} or {@link #parseOneRecord(CharSequence)} (if you want the output to be parsed line by line).

* *

The class is package visible, since it's used only in GitHistoryUtils - the class which retrieve various pieced of history information * in different formats from 'git log'

* *

Note that you may pass one set of options to the GitLogParser constructor and then execute git log with other set of options. - * In that case {@link #parse(String)} will parse only those options which you've specified in the constructor. + * In that case {@link #parse(CharSequence)} will parse only those options which you've specified in the constructor. * Others will be ignored since the parser knows nothing about them: it just gets the 'git log' output to parse. * Moreover you really must use {@link #getPretty()} to pass "--pretty=format" pattern to 'git log' - otherwise the parser won't be able * to parse output of 'git log' (because special separator characters are used for that).

@@ -158,7 +158,7 @@ public class GitLogParser { * The list is sorted as usual for git log - the first is the newest, the last is the oldest. */ @NotNull - List parse(@NotNull String output) { + List parse(@NotNull CharSequence output) { // Here is what git log returns for --pretty=tformat:^%H#%s$ // ^2c815939f45fbcfda9583f84b14fe9d393ada790#sample commit$ // @@ -166,20 +166,21 @@ public class GitLogParser { // ^b71477e9738168aa67a8d41c414f284255f81e8a#moved out$ // // R100 dir/anew.txt anew.txt - final List records = StringUtil.split(output, RECORD_START); // split by START, because END is the end of information, but not the end of the record: file status and path follow. + final List records = StringUtil.split(output, RECORD_START); // split by START, because END is the end of information, but not the end of the record: file status and path follow. String notMatchedPart = null; final List res = new ArrayList<>(records.size()); - for (String record : records) { - if (!record.trim().isEmpty()) { // record[0] is empty for sure, because we're splitting on RECORD_START. Just to play safe adding the check for all records. + for (CharSequence record : records) { + String recordString = record.toString(); + if (!recordString.isEmpty()) { // record[0] is empty for sure, because we're splitting on RECORD_START. Just to play safe adding the check for all records. if (notMatchedPart != null) { - record = notMatchedPart + record; + recordString = notMatchedPart + recordString; } - if (ONE_RECORD.matcher(record).matches()) { + if (ONE_RECORD.matcher(recordString).matches()) { notMatchedPart = null; - res.add(parseOneRecord(record)); + res.add(parseOneRecord(recordString)); } else { - notMatchedPart = record; + notMatchedPart = recordString; } } } @@ -194,17 +195,17 @@ public class GitLogParser { * @throws GitFormatException if the line is given in unexpected format. */ @Nullable - GitLogRecord parseOneRecord(@NotNull String line) { - if (line.isEmpty()) { + GitLogRecord parseOneRecord(@NotNull CharSequence line) { + if (line.length() == 0) { return null; } Matcher matcher = ONE_RECORD.matcher(line); if (!matcher.matches()) { - throwGFE("ONE_RECORD didn't match", line); + throwGFE("ONE_RECORD didn't match", line.toString()); } String commitInfo = matcher.group(1); if (commitInfo == null) { - throwGFE("No match for group#1 in", line); + throwGFE("No match for group#1 in", line.toString()); } final Map res = parseCommitInfo(commitInfo); @@ -216,7 +217,7 @@ public class GitLogParser { if (myNameStatusOption != NameStatus.NONE) { String pathsAndStatuses = matcher.group(2); if (pathsAndStatuses == null) { - throwGFE("No match for group#2 in", line); + throwGFE("No match for group#2 in", line.toString()); } if (myNameStatusOption == NameStatus.NAME) { From 4355d0f9927a6b48aa4ca1b330102ceddd1224db Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Fri, 7 Apr 2017 16:27:27 +0300 Subject: [PATCH 050/111] [git] avoid copying full git log output for throwing an exception --- .../src/git4idea/history/GitLogParser.java | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/plugins/git4idea/src/git4idea/history/GitLogParser.java b/plugins/git4idea/src/git4idea/history/GitLogParser.java index 49476cd15e4f..fb9975deb9dc 100644 --- a/plugins/git4idea/src/git4idea/history/GitLogParser.java +++ b/plugins/git4idea/src/git4idea/history/GitLogParser.java @@ -65,6 +65,8 @@ public class GitLogParser { public static final String RECORD_START_GIT = "%x01%x01"; private static final String ITEMS_SEPARATOR_GIT = "%x02"; private static final String RECORD_END_GIT = "%x03%x03"; + private static final int INPUT_ERROR_MESSAGE_HEAD_LIMIT = 1000000; // limit the string by ~2mb + private static final int INPUT_ERROR_MESSAGE_TAIL_LIMIT = 100; private final String myFormat; // pretty custom format generated in the constructor private final GitLogOption[] myOptions; @@ -201,11 +203,11 @@ public class GitLogParser { } Matcher matcher = ONE_RECORD.matcher(line); if (!matcher.matches()) { - throwGFE("ONE_RECORD didn't match", line.toString()); + throwGFE("ONE_RECORD didn't match", line); } String commitInfo = matcher.group(1); if (commitInfo == null) { - throwGFE("No match for group#1 in", line.toString()); + throwGFE("No match for group#1 in", line); } final Map res = parseCommitInfo(commitInfo); @@ -217,7 +219,7 @@ public class GitLogParser { if (myNameStatusOption != NameStatus.NONE) { String pathsAndStatuses = matcher.group(2); if (pathsAndStatuses == null) { - throwGFE("No match for group#2 in", line.toString()); + throwGFE("No match for group#2 in", line); } if (myNameStatusOption == NameStatus.NAME) { @@ -274,8 +276,18 @@ public class GitLogParser { } } - private static void throwGFE(String message, String line) { - throw new GitFormatException(message + " [" + StringUtil.escapeStringCharacters(line) + "]"); - } + private static void throwGFE(String message, @NotNull CharSequence line) { + String lineString; + String formatString = "%s...(%d more characters)...%s"; + if (line.length() > INPUT_ERROR_MESSAGE_HEAD_LIMIT + INPUT_ERROR_MESSAGE_TAIL_LIMIT + formatString.length()) { + lineString = String.format(formatString, line.subSequence(0, INPUT_ERROR_MESSAGE_HEAD_LIMIT), + (line.length() - INPUT_ERROR_MESSAGE_HEAD_LIMIT - INPUT_ERROR_MESSAGE_TAIL_LIMIT), + line.subSequence(line.length() - INPUT_ERROR_MESSAGE_TAIL_LIMIT, line.length())); + } + else { + lineString = line.toString(); + } + throw new GitFormatException(message + " [" + StringUtil.escapeStringCharacters(lineString) + "]"); + } } From de4403e82b8834db2c1a61abc14c0901d28b367d Mon Sep 17 00:00:00 2001 From: "Vladimir.Orlov" Date: Fri, 7 Apr 2017 16:32:27 +0300 Subject: [PATCH 051/111] Updater: fixed the case when symbolic links are not deleted. IDEA-170514 Codesign is broken after AppCode 2016.3.3 -> AppCode 2017.1 patch update --- updater/src/com/intellij/updater/Utils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/updater/src/com/intellij/updater/Utils.java b/updater/src/com/intellij/updater/Utils.java index 3ba24502a41d..9ddc5f528c02 100644 --- a/updater/src/com/intellij/updater/Utils.java +++ b/updater/src/com/intellij/updater/Utils.java @@ -73,7 +73,7 @@ public class Utils { public static void delete(File file) throws IOException { Path start = file.toPath(); - if (Files.exists(start)) { + if (Files.exists(start, LinkOption.NOFOLLOW_LINKS)) { Files.walkFileTree(start, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { From 59a2c555ca37cae1bb6c8ad71dac28bc5449c0a1 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Fri, 7 Apr 2017 16:39:06 +0300 Subject: [PATCH 052/111] IDEA-171094 Extract method object fails --- .../ExtractMethodObjectProcessor.java | 19 ++++------ .../RenameInInitializer.java | 8 +++++ .../RenameInInitializer.java.after | 35 +++++++++++++++++++ ...ethodObjectWithMultipleExitPointsTest.java | 8 +++++ 4 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/RenameInInitializer.java create mode 100644 java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/RenameInInitializer.java.after diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java index 4445064de890..96532f8c8076 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java @@ -339,15 +339,7 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { for (PsiVariable variable : outputVariables) { PsiVariable var = (PsiVariable)declaredElement; if (Comparing.strEqual(var.getName(), variable.getName())) { - PsiExpression initializer = var.getInitializer(); - if (initializer == null) { - replacementMap.put(var, null); - } - else { - PsiStatement assignmentStatement = myElementFactory - .createStatementFromText(var2FieldNames.get(variable.getName()) + " = " + initializer.getText() + ";", statement); - replacementMap.put(var, assignmentStatement); - } + replacementMap.put(var, var.getInitializer()); } } } @@ -412,11 +404,14 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor { } } else if (statement instanceof PsiLocalVariable) { - PsiLocalVariable variable = (PsiLocalVariable)statement; + final PsiLocalVariable variable = (PsiLocalVariable)statement; variable.normalizeDeclaration(); - PsiDeclarationStatement declaration = PsiTreeUtil.getParentOfType(statement, PsiDeclarationStatement.class); + final PsiExpression initializer = variable.getInitializer(); + LOG.assertTrue(initializer != null); + final PsiStatement assignmentStatement = myElementFactory.createStatementFromText(var2FieldNames.get(variable.getName()) + " = " + initializer.getText() + ";", statement); + final PsiDeclarationStatement declaration = PsiTreeUtil.getParentOfType(statement, PsiDeclarationStatement.class); LOG.assertTrue(declaration != null); - declaration.replace(replacement); + declaration.replace(assignmentStatement); } else { if (statement instanceof PsiReturnStatement) { diff --git a/java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/RenameInInitializer.java b/java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/RenameInInitializer.java new file mode 100644 index 000000000000..4f1fa3457c20 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/RenameInInitializer.java @@ -0,0 +1,8 @@ +public class RenameInInitializer { + public static void main(String[] args) { + int aValue = 100; + int result = 1000; + int a = IntStream.of(aValue, result).peek(x -> {}).sum(); + System.out.println(aValue + result + a); + } +} diff --git a/java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/RenameInInitializer.java.after b/java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/RenameInInitializer.java.after new file mode 100644 index 000000000000..9d4106c46485 --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethodObject/multipleExitPoints/RenameInInitializer.java.after @@ -0,0 +1,35 @@ +public class RenameInInitializer { + public static void main(String[] args) { + Inner inner = new Inner().invoke(); + int aValue = inner.getValue(); + int result = inner.getResult(); + int a = inner.getA(); + System.out.println(aValue + result + a); + } + + private static class Inner { + private int myValue; + private int myResult; + private int myA; + + public int getValue() { + return myValue; + } + + public int getResult() { + return myResult; + } + + public int getA() { + return myA; + } + + public Inner invoke() { + myValue = 100; + myResult = 1000; + myA = IntStream.of(myValue, myResult).peek(x -> { + }).sum(); + return this; + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObjectWithMultipleExitPointsTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObjectWithMultipleExitPointsTest.java index b2e56e5f756d..8deca9cc7e52 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObjectWithMultipleExitPointsTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObjectWithMultipleExitPointsTest.java @@ -152,7 +152,15 @@ public class ExtractMethodObjectWithMultipleExitPointsTest extends LightRefactor doTest(); } + public void testRenameInInitializer() throws Exception { + doTestWithIdeaCodeStyleSettings(); + } + public void testSameFieldsWithPrefix() throws Exception { + doTestWithIdeaCodeStyleSettings(); + } + + private void doTestWithIdeaCodeStyleSettings() throws Exception { final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()); String oldPrefix = settings.FIELD_NAME_PREFIX; settings.FIELD_NAME_PREFIX = "my"; From 9d408ae4b02f3fba11903cdf15e4dab88b7709ac Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Fri, 7 Apr 2017 16:45:52 +0300 Subject: [PATCH 053/111] IDEA-168273 fix disabled combobox foreground color --- .../com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java index 4a913447988c..ebe14a4068a6 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/MacIntelliJComboBoxUI.java @@ -368,6 +368,7 @@ public class MacIntelliJComboBoxUI extends BasicComboBoxUI { Rectangle bounds = rectangleForCurrentValue(); if ( !comboBox.isEditable() ) { + listBox.setForeground(comboBox.isEnabled() ? UIManager.getColor("Label.foreground") : UIManager.getColor("Label.disabledForeground")); paintCurrentValue(g, bounds, comboBox.isPopupVisible()); } } From 9171e27001b8295b78f3921a72c3d9dda581b8d8 Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Fri, 7 Apr 2017 16:46:28 +0300 Subject: [PATCH 054/111] IDEA-168758 Tabs of debugger tool window are cut from below with 4K resolution --- .../com/intellij/execution/ui/layout/impl/JBRunnerTabs.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/JBRunnerTabs.java b/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/JBRunnerTabs.java index 0b2226504b30..2576802954d8 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/JBRunnerTabs.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/layout/impl/JBRunnerTabs.java @@ -26,12 +26,12 @@ import com.intellij.ui.tabs.UiDecorator; import com.intellij.ui.tabs.impl.JBEditorTabs; import com.intellij.ui.tabs.impl.JBTabsImpl; import com.intellij.ui.tabs.impl.TabLabel; -import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import javax.swing.border.EmptyBorder; import java.awt.*; import java.util.Map; @@ -107,7 +107,7 @@ public class JBRunnerTabs extends JBEditorTabs { @Override public void apply(UiDecorator.UiDecoration decoration) { - setBorder(JBUI.Borders.empty(5, 5, 7, 5)); + setBorder(new EmptyBorder(5, 5, 7, 5));//Don't use JBUI here, it clips tab text in case of HiDPI } @Override From a31c85b322e23fbbdb1bbbd2b3c6c2e44aa98b0b Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 7 Apr 2017 15:59:54 +0200 Subject: [PATCH 055/111] [tests] test case for IDEA-CR-20127 --- updater/testSrc/com/intellij/updater/UtilsTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/updater/testSrc/com/intellij/updater/UtilsTest.java b/updater/testSrc/com/intellij/updater/UtilsTest.java index 2fa9ec1bcf2d..f45dfa1974b9 100644 --- a/updater/testSrc/com/intellij/updater/UtilsTest.java +++ b/updater/testSrc/com/intellij/updater/UtilsTest.java @@ -129,4 +129,17 @@ public class UtilsTest { assertFalse(link.exists()); assertThat(dir.listFiles()).containsExactly(file); } + + @Test + public void testDeleteDanglingSymlink() throws Exception { + assumeTrue(!IS_WINDOWS); + + File dir = tempDir.newFolder("temp_dir"); + File link = new File(dir, "link"); + Utils.createLink("dangling", link); + assertThat(dir.listFiles()).containsExactly(link); + + Utils.delete(link); + assertThat(dir.listFiles()).isEmpty(); + } } \ No newline at end of file From 4c663061717d9774642fee6719c9b757f59abc3b Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 28 Mar 2017 17:11:39 +0300 Subject: [PATCH 056/111] android 2.3 merge --- .../src/com/intellij/designer/LightToolWindowManager.java | 2 +- .../intellij/openapi/fileEditor/impl/EditorHistoryManager.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/designer/LightToolWindowManager.java b/platform/platform-impl/src/com/intellij/designer/LightToolWindowManager.java index 1ad75ae19716..ed47e0d868e4 100644 --- a/platform/platform-impl/src/com/intellij/designer/LightToolWindowManager.java +++ b/platform/platform-impl/src/com/intellij/designer/LightToolWindowManager.java @@ -262,7 +262,7 @@ public abstract class LightToolWindowManager implements ProjectComponent { } @Nullable - final ToolWindowAnchor getEditorMode() { + public final ToolWindowAnchor getEditorMode() { String value = myPropertiesComponent.getValue(myEditorModeKey); if (value == null) { return getAnchor(); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java index d8c4954d226a..c40b712289e0 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java @@ -267,7 +267,7 @@ public final class EditorHistoryManager implements PersistentStateComponent Date: Mon, 3 Apr 2017 14:58:13 +0300 Subject: [PATCH 057/111] android 2.3 merge: licenses --- .../jetbrains/intellij/build/CommunityLibraryLicenses.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy index cc579576ec08..9a04a5cf841c 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy @@ -40,7 +40,8 @@ class CommunityLibraryLicenses { new LibraryLicense(name: "Android SDK Tools JPS", libraryName: "android-sdk-tools-jps", license: "Apache 2.0", url: "http://source.android.com/"), new LibraryLicense(name: "Android SDK Tools", libraryName: "android-sdk-tools", license: "Apache 2.0", url: "http://source.android.com/"), - new LibraryLicense(name: "Android Analytics", libraryName: "analytics", license: "Apache 2.0", url: "http://source.android.com/"), + new LibraryLicense(name: "Android Analytics", libraryName: "google-analytics-library", license: "Apache 2.0", url: "http://source.android.com/"), + new LibraryLicense(name: "Android Profiler", libraryName: "studio-profiler-grpc-1.0-jarjar", license: "Apache 2.0", url: "http://source.android.com/"), new LibraryLicense(name: "Android Layout Library", libraryName: "layoutlib", license: "Apache 2.0", url: "http://source.android.com/"), new LibraryLicense(name: "Android DEX library", libraryName: "dexlib2", license: "Apache 2.0", url: "http://source.android.com/"), new LibraryLicense(name: "Android Sherpa library", libraryName: "sherpa-solver", license: "Apache 2.0", url: "http://source.android.com/"), From 9b621ac35fb6538a4bbe57ac1448cde8aee99a74 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 4 Apr 2017 14:39:54 +0300 Subject: [PATCH 058/111] android 2.3 merge: layout --- .../build/CommunityRepositoryModules.groovy | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy index 54896406ad6d..043c006e0503 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy @@ -239,17 +239,23 @@ class CommunityRepositoryModules { static PluginLayout androidPlugin(Map additionalModulesToJars) { plugin("android") { + withModule("android-plugin", "android.jar") + withModule("observable", "android.jar") + withModule("wizard", "android.jar") + withModule("sdk-updates", "android.jar") + withModule("designer", "android.jar") + withModule("manifest-merger") + withModule("repository") + withModule("common", "android-base-common.jar") withModule("android-common", "android-common.jar", false) withModule("android-rt", "android-rt.jar", false) withModule("android-annotations", "androidAnnotations.jar") - withModule("common") withModule("sdklib", "sdklib.jar") withModule("sdk-common", "sdk-common.jar") withModule("layoutlib-api", "layoutlib-api.jar") withModule("layoutlib", "layoutlib-loader.jar") - withModule("manifest-merger") withModule("adt-ui", "adt-ui.jar") - withModule("repository") + withModule("adt-ui-model", "adt-ui.jar") withModule("sherpa-ui", "constraint-layout.jar") withModule("pixelprobe", "pixalprobe.jar") withModule("manifest-merger", "manifest-merger.jar") @@ -261,7 +267,6 @@ class CommunityRepositoryModules { withModule("lint-checks", "sdk-tools.jar") withModule("ninepatch", "sdk-tools.jar") withModule("perflib", "sdk-tools.jar") - withModule("rpclib", "sdk-tools.jar") withModule("builder-model", "sdk-tools.jar") withModule("builder-test-api", "sdk-tools.jar") withModule("instant-run-common", "sdk-tools.jar") @@ -270,7 +275,6 @@ class CommunityRepositoryModules { withModule("android-gradle-jps", "jps/android-gradle-jps.jar", false) withModule("android-jps-plugin", "jps/android-jps-plugin.jar", false) withProjectLibrary("freemarker-2.3.20") //todo[nik] move to module libraries - withProjectLibrary("builder-model") //todo[nik] move to module libraries withProjectLibrary("jgraphx-3.4.0.1") //todo[nik] move to module libraries withProjectLibrary("kxml2") //todo[nik] move to module libraries withProjectLibrary("lombok-ast") //todo[nik] move to module libraries @@ -288,6 +292,7 @@ class CommunityRepositoryModules { withResource("lib/javawriter-2.2.1.jar", "lib") withResource("lib/juniversalchardet-1.0.3.jar", "lib") withResource("lib/layoutlib.jar", "lib") + withResource("lib/google-analytics-library.jar", "lib") withResource("lib/gluegen-rt.jar", "lib") withResource("lib/gluegen-rt-natives-linux-amd64.jar", "lib") withResource("lib/gluegen-rt-natives-linux-i586.jar", "lib") From 00ca58677558bd2d97db9da36ea565f571af95f7 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Tue, 4 Apr 2017 15:21:13 +0300 Subject: [PATCH 059/111] android 2.3: community missed library --- .idea/libraries/dexlib2.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .idea/libraries/dexlib2.xml diff --git a/.idea/libraries/dexlib2.xml b/.idea/libraries/dexlib2.xml new file mode 100644 index 000000000000..b38e3790e09d --- /dev/null +++ b/.idea/libraries/dexlib2.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file From f0023eaf03b567529f27c8a7eeed12945ad2264e Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Thu, 6 Apr 2017 17:37:43 +0300 Subject: [PATCH 060/111] running AS from community sources --- .idea/runConfigurations/Android_Studio.xml | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .idea/runConfigurations/Android_Studio.xml diff --git a/.idea/runConfigurations/Android_Studio.xml b/.idea/runConfigurations/Android_Studio.xml new file mode 100644 index 000000000000..8019da516f41 --- /dev/null +++ b/.idea/runConfigurations/Android_Studio.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file From d8f6d547c40324ed2fa7fc73d34949b566268b56 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Thu, 6 Apr 2017 18:04:24 +0300 Subject: [PATCH 061/111] android 2.3: fixing plugin layout --- .../org/jetbrains/intellij/build/BaseIdeaProperties.groovy | 2 +- .../intellij/build/CommunityRepositoryModules.groovy | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/build/groovy/org/jetbrains/intellij/build/BaseIdeaProperties.groovy b/build/groovy/org/jetbrains/intellij/build/BaseIdeaProperties.groovy index 837dd3668a0d..82a78e76ae37 100644 --- a/build/groovy/org/jetbrains/intellij/build/BaseIdeaProperties.groovy +++ b/build/groovy/org/jetbrains/intellij/build/BaseIdeaProperties.groovy @@ -65,7 +65,7 @@ abstract class BaseIdeaProperties extends ProductProperties { "tasks-core", "tasks-java", "maven", "gradle", "git4idea", "remote-servers-git", "remote-servers-git-java", "svn4idea", "hg4idea", "github", "cvs-plugin", - "jetgroovy", "junit", "testng", "xpath", "xslt-debugger", "android", "javaFX-CE", + "jetgroovy", "junit", "testng", "xpath", "xslt-debugger", "android-plugin", "javaFX-CE", "java-i18n", "ant", "ui-designer", "ByteCodeViewer", "coverage", "java-decompiler-plugin", "devkit", "eclipse", "IntelliLang", "IntelliLang-java", "IntelliLang-xml", "intellilang-jps-plugin" ] diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy index 043c006e0503..7e39dc2c5b0c 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy @@ -238,8 +238,10 @@ class CommunityRepositoryModules { ] static PluginLayout androidPlugin(Map additionalModulesToJars) { - plugin("android") { - withModule("android-plugin", "android.jar") + plugin("android-plugin") { + mainJarName = "android.jar" + directoryName = "android" + withModule("android", "android.jar") withModule("observable", "android.jar") withModule("wizard", "android.jar") withModule("sdk-updates", "android.jar") From 737a8993af31063cabd8f91e609a5a308d0b5e4a Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Thu, 6 Apr 2017 20:47:25 +0300 Subject: [PATCH 062/111] TreeGridTest fixed --- .../platform-impl/src/com/intellij/ui/ListSpeedSearch.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/ui/ListSpeedSearch.java b/platform/platform-impl/src/com/intellij/ui/ListSpeedSearch.java index e6415812f966..88248e6cafb6 100644 --- a/platform/platform-impl/src/com/intellij/ui/ListSpeedSearch.java +++ b/platform/platform-impl/src/com/intellij/ui/ListSpeedSearch.java @@ -16,6 +16,7 @@ package com.intellij.ui; import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.project.DumbAwareAction; @@ -108,7 +109,10 @@ public class ListSpeedSearch extends SpeedSearchBase { public MySelectAllAction(@NotNull JList list, @NotNull ListSpeedSearch search) { myList = list; mySearch = search; - copyShortcutFrom(ActionManager.getInstance().getAction(IdeActions.ACTION_SELECT_ALL)); + AnAction action = ActionManager.getInstance().getAction(IdeActions.ACTION_SELECT_ALL); + if (action != null) { + copyShortcutFrom(action); + } setEnabledInModalContext(true); } From ef488ca62f3504220d97d1292dc7db7880a4a019 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Thu, 6 Apr 2017 20:51:16 +0300 Subject: [PATCH 063/111] android tests bombed --- platform/testFramework/testSrc/tests/testGroups.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/testFramework/testSrc/tests/testGroups.properties b/platform/testFramework/testSrc/tests/testGroups.properties index 33cab98b4005..3909d1b0e76f 100644 --- a/platform/testFramework/testSrc/tests/testGroups.properties +++ b/platform/testFramework/testSrc/tests/testGroups.properties @@ -150,6 +150,7 @@ org.jetbrains.android.jps.AndroidBuilderTest com.android.tools.idea.gradle.service.notification.hyperlink.CustomNotificationListenerTest com.android.repository.impl.installer.BasicInstallerTest org.jetbrains.android.AndroidLintTest +com.android.tools.adtui.workbench.* [GRADLE_INTEGRATION_TESTS] org.jetbrains.plugins.gradle.importing.* From 63a8259f0b26ec0e989f95329bcf0d88da1cbaaf Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Thu, 6 Apr 2017 21:11:01 +0300 Subject: [PATCH 064/111] android layout fixed --- .../build/CommunityRepositoryModules.groovy | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy index 7e39dc2c5b0c..191e75c28f35 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy @@ -281,33 +281,33 @@ class CommunityRepositoryModules { withProjectLibrary("kxml2") //todo[nik] move to module libraries withProjectLibrary("lombok-ast") //todo[nik] move to module libraries withProjectLibrary("layoutlib") //todo[nik] move to module libraries - withResource("device-art-resources", "lib/device-art-resources") + withResource("../android/device-art-resources", "lib/device-art-resources") withResourceFromModule("layoutlib-resources", ".", "lib/layoutlib") withResourceFromModule("sdklib", "../templates", "lib/templates") - withResourceArchive("annotations", "lib/androidAnnotations.jar") - withResource("lib/antlr4-runtime-4.5.3.jar", "lib") - withResource("lib/asm-5.0.3.jar", "lib") - withResource("lib/asm-analysis-5.0.3.jar", "lib") - withResource("lib/asm-tree-5.0.3.jar", "lib") - withResource("lib/commons-io-2.4.jar", "lib") - withResource("lib/commons-compress-1.8.1.jar", "lib") - withResource("lib/javawriter-2.2.1.jar", "lib") - withResource("lib/juniversalchardet-1.0.3.jar", "lib") - withResource("lib/layoutlib.jar", "lib") - withResource("lib/google-analytics-library.jar", "lib") - withResource("lib/gluegen-rt.jar", "lib") - withResource("lib/gluegen-rt-natives-linux-amd64.jar", "lib") - withResource("lib/gluegen-rt-natives-linux-i586.jar", "lib") - withResource("lib/gluegen-rt-natives-macosx-universal.jar", "lib") - withResource("lib/gluegen-rt-natives-windows-amd64.jar", "lib") - withResource("lib/gluegen-rt-natives-windows-i586.jar", "lib") + withResourceArchive("../android/annotations", "lib/androidAnnotations.jar") + withResource("../android/lib/antlr4-runtime-4.5.3.jar", "lib") + withResource("../android/lib/asm-5.0.3.jar", "lib") + withResource("../android/lib/asm-analysis-5.0.3.jar", "lib") + withResource("../android/lib/asm-tree-5.0.3.jar", "lib") + withResource("../android/lib/commons-io-2.4.jar", "lib") + withResource("../android/lib/commons-compress-1.8.1.jar", "lib") + withResource("../android/lib/javawriter-2.2.1.jar", "lib") + withResource("../android/lib/juniversalchardet-1.0.3.jar", "lib") + withResource("../android/lib/layoutlib.jar", "lib") + withResource("../android/lib/google-analytics-library.jar", "lib") + withResource("../android/lib/gluegen-rt.jar", "lib") + withResource("../android/lib/gluegen-rt-natives-linux-amd64.jar", "lib") + withResource("../android/lib/gluegen-rt-natives-linux-i586.jar", "lib") + withResource("../android/lib/gluegen-rt-natives-macosx-universal.jar", "lib") + withResource("../android/lib/gluegen-rt-natives-windows-amd64.jar", "lib") + withResource("../android/lib/gluegen-rt-natives-windows-i586.jar", "lib") withProjectLibrary("jogl-all") //todo[nik] move to module libraries - withResource("lib/jogl-all-natives-linux-amd64.jar", "lib") - withResource("lib/jogl-all-natives-linux-i586.jar", "lib") - withResource("lib/jogl-all-natives-macosx-universal.jar", "lib") - withResource("lib/jogl-all-natives-windows-amd64.jar", "lib") - withResource("lib/jogl-all-natives-windows-i586.jar", "lib") - withResource("lib/androidWidgets", "lib/androidWidgets") + withResource("../android/lib/jogl-all-natives-linux-amd64.jar", "lib") + withResource("../android/lib/jogl-all-natives-linux-i586.jar", "lib") + withResource("../android/lib/jogl-all-natives-macosx-universal.jar", "lib") + withResource("../android/lib/jogl-all-natives-windows-amd64.jar", "lib") + withResource("../android/lib/jogl-all-natives-windows-i586.jar", "lib") + withResource("../android/lib/androidWidgets", "lib/androidWidgets") additionalModulesToJars.entrySet().each { withModule(it.key, it.value) } From efd9e3edd03a5e8cd5e7213808552a5f60c4cac8 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 7 Apr 2017 13:02:26 +0300 Subject: [PATCH 065/111] android adt-ui tests bombed due to timer problem --- platform/testFramework/testSrc/tests/testGroups.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/testFramework/testSrc/tests/testGroups.properties b/platform/testFramework/testSrc/tests/testGroups.properties index 3909d1b0e76f..97b9ab71446d 100644 --- a/platform/testFramework/testSrc/tests/testGroups.properties +++ b/platform/testFramework/testSrc/tests/testGroups.properties @@ -150,7 +150,7 @@ org.jetbrains.android.jps.AndroidBuilderTest com.android.tools.idea.gradle.service.notification.hyperlink.CustomNotificationListenerTest com.android.repository.impl.installer.BasicInstallerTest org.jetbrains.android.AndroidLintTest -com.android.tools.adtui.workbench.* +com.android.tools.adtui.* [GRADLE_INTEGRATION_TESTS] org.jetbrains.plugins.gradle.importing.* From 66ef684787437391a1b250289ee4e917cf8e279a Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 7 Apr 2017 16:24:09 +0300 Subject: [PATCH 066/111] android 2.3 merge: test bombed --- platform/testFramework/testSrc/tests/testGroups.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/testFramework/testSrc/tests/testGroups.properties b/platform/testFramework/testSrc/tests/testGroups.properties index 97b9ab71446d..9c44a1ef0514 100644 --- a/platform/testFramework/testSrc/tests/testGroups.properties +++ b/platform/testFramework/testSrc/tests/testGroups.properties @@ -151,6 +151,7 @@ com.android.tools.idea.gradle.service.notification.hyperlink.CustomNotificationL com.android.repository.impl.installer.BasicInstallerTest org.jetbrains.android.AndroidLintTest com.android.tools.adtui.* +com.android.builder.model.VersionTest [GRADLE_INTEGRATION_TESTS] org.jetbrains.plugins.gradle.importing.* From 8895665cd3a2deec12c1359e3d3101b67afab11c Mon Sep 17 00:00:00 2001 From: Anton Tarasov Date: Fri, 7 Apr 2017 17:32:58 +0300 Subject: [PATCH 067/111] JRE-267 Cannot run program java should be java.exe on Windows --- platform/platform-impl/src/com/intellij/util/JdkBundle.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/util/JdkBundle.java b/platform/platform-impl/src/com/intellij/util/JdkBundle.java index da2981831826..e737db7daaf1 100644 --- a/platform/platform-impl/src/com/intellij/util/JdkBundle.java +++ b/platform/platform-impl/src/com/intellij/util/JdkBundle.java @@ -204,9 +204,10 @@ public class JdkBundle { private static Pair, Pair> getJDKNameArchVersionAndUpdate(File jvm, String homeSubPath) { GeneralCommandLine commandLine = new GeneralCommandLine().withParentEnvironmentType(GeneralCommandLine.ParentEnvironmentType.NONE); - File jvmPath = new File(jvm, homeSubPath + File.separator + "jre" + File.separator + "bin" + File.separator + "java"); + String javaExecutable = "java" + (SystemInfo.isWindows ? ".exe" : ""); + File jvmPath = new File(jvm, homeSubPath + File.separator + "jre" + File.separator + "bin" + File.separator + javaExecutable); if (!jvmPath.exists()) { - jvmPath = new File(jvm, homeSubPath + File.separator + "bin" + File.separator + "java"); + jvmPath = new File(jvm, homeSubPath + File.separator + "bin" + File.separator + javaExecutable); } commandLine.setExePath(jvmPath.getAbsolutePath()); commandLine.addParameter("-version"); From 527cd924cf4fb2d2f673e6da056f1e63387a5e36 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 7 Apr 2017 17:50:51 +0300 Subject: [PATCH 068/111] android 2.3: community project files --- .idea/libraries/google_analytics_library.xml | 9 ++++++++ .idea/libraries/sherpa_solver.xml | 2 +- .../studio_profiler_grpc_1_0_jarjar.xml | 9 ++++++++ .idea/modules.xml | 23 ++++++++++++------- 4 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 .idea/libraries/google_analytics_library.xml create mode 100644 .idea/libraries/studio_profiler_grpc_1_0_jarjar.xml diff --git a/.idea/libraries/google_analytics_library.xml b/.idea/libraries/google_analytics_library.xml new file mode 100644 index 000000000000..4065f2b9e542 --- /dev/null +++ b/.idea/libraries/google_analytics_library.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/sherpa_solver.xml b/.idea/libraries/sherpa_solver.xml index b0cca4264467..dafc23b05b18 100644 --- a/.idea/libraries/sherpa_solver.xml +++ b/.idea/libraries/sherpa_solver.xml @@ -1,7 +1,7 @@ - + diff --git a/.idea/libraries/studio_profiler_grpc_1_0_jarjar.xml b/.idea/libraries/studio_profiler_grpc_1_0_jarjar.xml new file mode 100644 index 000000000000..16ebb4312e9c --- /dev/null +++ b/.idea/libraries/studio_profiler_grpc_1_0_jarjar.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 3455ca934d71..40c5ad631ac4 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -3,6 +3,7 @@ + @@ -12,15 +13,17 @@ + - + - - + + + @@ -65,6 +68,7 @@ + @@ -190,7 +194,9 @@ + + @@ -200,6 +206,8 @@ + + @@ -211,6 +219,7 @@ + @@ -236,14 +245,13 @@ - + - - + @@ -252,7 +260,6 @@ - @@ -290,6 +297,7 @@ + @@ -307,7 +315,6 @@ - \ No newline at end of file From 8c889b01cd0aeed3e80de190c35ab4d7501c47f5 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 7 Apr 2017 18:02:16 +0300 Subject: [PATCH 069/111] obsolete library removed --- .idea/libraries/builder_model.xml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 .idea/libraries/builder_model.xml diff --git a/.idea/libraries/builder_model.xml b/.idea/libraries/builder_model.xml deleted file mode 100644 index 194983c4ed4c..000000000000 --- a/.idea/libraries/builder_model.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file From 1a38bcccb5fe45be1b04ffc3c9d177b803fd0dc0 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Fri, 7 Apr 2017 18:02:43 +0300 Subject: [PATCH 070/111] android plugin for community --- community-main.iml | 1 + 1 file changed, 1 insertion(+) diff --git a/community-main.iml b/community-main.iml index 8f57ec84e1cc..ba81bf74570e 100644 --- a/community-main.iml +++ b/community-main.iml @@ -123,5 +123,6 @@ + \ No newline at end of file From 7d957c7320004d7594e639d88da3787650b8864a Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Fri, 7 Apr 2017 18:16:49 +0300 Subject: [PATCH 071/111] [git] inline createRevision method that is short and used only once --- plugins/git4idea/src/git4idea/GitContentRevision.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plugins/git4idea/src/git4idea/GitContentRevision.java b/plugins/git4idea/src/git4idea/GitContentRevision.java index 30a2eaeddf69..9aee7df20de0 100644 --- a/plugins/git4idea/src/git4idea/GitContentRevision.java +++ b/plugins/git4idea/src/git4idea/GitContentRevision.java @@ -191,13 +191,8 @@ public class GitContentRevision implements ByteBackedContentRevision { public static ContentRevision createRevision(@NotNull final VirtualFile file, @Nullable final VcsRevisionNumber revisionNumber, @NotNull final Project project) { - return createRevision(file, revisionNumber, project, null); - } - - public static ContentRevision createRevision(@NotNull final VirtualFile file, @Nullable final VcsRevisionNumber revisionNumber, - @NotNull final Project project, @Nullable final Charset charset) { - final FilePath filePath = VcsUtil.getFilePath(file); - return createRevision(filePath, revisionNumber, project, charset); + FilePath filePath = VcsUtil.getFilePath(file); + return createRevision(filePath, revisionNumber, project, null); } public static ContentRevision createRevision(@NotNull final FilePath filePath, @Nullable final VcsRevisionNumber revisionNumber, From bc872fd41b948d6e55ff7c5e7fc2f9c3187b2ace Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 7 Apr 2017 16:14:15 +0100 Subject: [PATCH 072/111] Don't check for disposed project: makes no sense w/o read action --- plugins/git4idea/src/git4idea/GitContentRevision.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/git4idea/src/git4idea/GitContentRevision.java b/plugins/git4idea/src/git4idea/GitContentRevision.java index 9aee7df20de0..411d3bc82e66 100644 --- a/plugins/git4idea/src/git4idea/GitContentRevision.java +++ b/plugins/git4idea/src/git4idea/GitContentRevision.java @@ -141,12 +141,7 @@ public class GitContentRevision implements ByteBackedContentRevision { @Nullable VcsRevisionNumber revisionNumber, Project project, boolean isDeleted, final boolean canBeDeleted, boolean unescapePath) throws VcsException { - final FilePath file; - if (project.isDisposed()) { - file = VcsUtil.getFilePath(makeAbsolutePath(vcsRoot, path, unescapePath), false); - } else { - file = createPath(vcsRoot, path, isDeleted, canBeDeleted, unescapePath); - } + FilePath file = createPath(vcsRoot, path, isDeleted, canBeDeleted, unescapePath); return createRevision(file, revisionNumber, project); } From 150b68edae1d39e0b4b58a997bc7e2591ebfd582 Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Fri, 7 Apr 2017 17:13:21 +0300 Subject: [PATCH 073/111] Add check if we're in course creator mode --- .../jetbrains/edu/coursecreator/CCProjectComponent.java | 8 +++++--- .../edu/coursecreator/CCVirtualFileListener.java | 4 +--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java index 61d0323f968c..94573e76c17c 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java @@ -104,9 +104,11 @@ public class CCProjectComponent extends AbstractProjectComponent { } public void projectOpened() { - migrateIfNeeded(); - VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener); - EduUsagesCollector.projectTypeOpened(CCUtils.COURSE_MODE); + if (CCUtils.isCourseCreator(myProject)) { + migrateIfNeeded(); + VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener); + EduUsagesCollector.projectTypeOpened(CCUtils.COURSE_MODE); + } } public void projectClosed() { diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java index cfc2e0dd636b..7a2f28b61b4a 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java @@ -16,8 +16,6 @@ import com.jetbrains.edu.learning.courseFormat.TaskFile; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import org.jetbrains.annotations.NotNull; -import java.io.File; - public class CCVirtualFileListener implements VirtualFileListener { @Override @@ -37,7 +35,7 @@ public class CCVirtualFileListener implements VirtualFileListener { return; } Course course = StudyTaskManager.getInstance(project).getCourse(); - if (course == null || !CCUtils.isCourseCreator(project)) { + if (course == null) { return; } TaskFile taskFile = StudyUtils.getTaskFile(project, createdFile); From 9b2eef91e83dbdd06cf30ecd7cbea11ce93e6afe Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Fri, 7 Apr 2017 18:02:23 +0300 Subject: [PATCH 074/111] Use StudyNavigator.createTask to update task content for a new recommended task --- .../courseGeneration/StudyGenerator.java | 4 +- .../stepic/EduAdaptiveStepicConnector.java | 59 ++++--------------- 2 files changed, 14 insertions(+), 49 deletions(-) diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseGeneration/StudyGenerator.java b/python/educational-core/src/com/jetbrains/edu/learning/courseGeneration/StudyGenerator.java index dad0e77a7d64..1fed74118ab7 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseGeneration/StudyGenerator.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseGeneration/StudyGenerator.java @@ -73,7 +73,7 @@ public class StudyGenerator { createChildFile(taskDir, name, taskFile.text); } - public static void createDescriptions(VirtualFile taskDir, Task task) throws IOException { + private static void createDescriptions(VirtualFile taskDir, Task task) throws IOException { final Map texts = task.getTaskTexts(); for (Map.Entry entry : texts.entrySet()) { final String name = entry.getKey(); @@ -82,7 +82,7 @@ public class StudyGenerator { } } - public static void createTestFiles(VirtualFile taskDir, Task task) throws IOException { + private static void createTestFiles(VirtualFile taskDir, Task task) throws IOException { final Map tests = task.getTestsText(); for (Map.Entry entry : tests.entrySet()) { final String name = entry.getKey(); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java index 755ea42119ec..c8af73b7b3c8 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java @@ -7,14 +7,12 @@ import com.intellij.ide.projectView.ProjectView; import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.jetbrains.edu.learning.StudySettings; @@ -49,7 +47,10 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; import java.util.concurrent.TimeUnit; import static com.jetbrains.edu.learning.stepic.EduStepicConnector.getStep; @@ -320,7 +321,7 @@ public class EduAdaptiveStepicConnector { task.initTask(lesson, false); boolean replaceCurrentTask = reactionToPost == TOO_HARD_RECOMMENDATION_REACTION || reactionToPost == TOO_BORING_RECOMMENDATION_REACTION; if (replaceCurrentTask) { - replaceCurrentTask(project, editor, task, lesson); + replaceCurrentTask(project, task, lesson); } else { addAsNextTask(project, task, lesson); @@ -361,7 +362,7 @@ public class EduAdaptiveStepicConnector { } } - private static void replaceCurrentTask(@NotNull Project project, @NotNull StudyEditor editor, @NotNull Task task, @NotNull Lesson lesson) { + private static void replaceCurrentTask(@NotNull Project project, @NotNull Task task, @NotNull Lesson lesson) { Course course = StudyTaskManager.getInstance(project).getCourse(); assert course != null; @@ -370,8 +371,6 @@ public class EduAdaptiveStepicConnector { task.setIndex(taskIndex); lesson.getTaskList().set(taskIndex - 1, task); - copyTaskFileParameters(editor, task); - final String lessonName = EduNames.LESSON + lesson.getIndex(); updateProjectFiles(project, task, lessonName); setToolWindowText(project, task); @@ -380,12 +379,10 @@ public class EduAdaptiveStepicConnector { private static void updateProjectFiles(@NotNull Project project, @NotNull Task task, @NotNull String lessonName) { final VirtualFile lessonDir = project.getBaseDir().findChild(lessonName); if (lessonDir != null) { - final VirtualFile taskResourceRoot = lessonDir.findChild(EduNames.TASK + task.getIndex()); ApplicationManager.getApplication().invokeLater(() -> ApplicationManager.getApplication().runWriteAction(() -> { try { - removeOldProjectFiles(project, taskResourceRoot); - StudyGenerator.createTestFiles(taskResourceRoot, task); - StudyGenerator.createDescriptions(taskResourceRoot, task); + removeOldProjectFiles(lessonDir, task.getIndex()); + StudyGenerator.createTask(task, lessonDir); } catch (IOException e) { LOG.warn(e.getMessage()); @@ -394,46 +391,14 @@ public class EduAdaptiveStepicConnector { } } - private static void removeOldProjectFiles(@NotNull Project project, @Nullable VirtualFile taskRecourseRoot) throws IOException { - if (taskRecourseRoot == null) { + private static void removeOldProjectFiles(@NotNull VirtualFile lessonDir, int taskIndex) throws IOException { + final VirtualFile taskDir = lessonDir.findChild(EduNames.TASK + taskIndex); + if (taskDir == null) { LOG.warn("Failed to update files for a new recommendation: task directory is null"); return; } - VirtualFile[] children = VfsUtil.getChildren(taskRecourseRoot); - for (VirtualFile file : children) { - String name = file.getName(); - if (StudyUtils.isTestsFile(project, name) || StudyUtils.isTaskDescriptionFile(name)) { - file.delete(taskRecourseRoot); - } - } - } - - private static void copyTaskFileParameters(@NotNull StudyEditor editor, @NotNull Task task) { - final Map taskFiles = task.getTaskFiles(); - if (taskFiles.size() == 1) { - TaskFile newTaskFile = (TaskFile)taskFiles.values().toArray()[0]; - setTaskFileParameters(editor, task, newTaskFile); - updateEditorText(editor, newTaskFile); - } - else { - LOG.warn("Got task without unexpected number of task files: " + taskFiles.size()); - } - } - private static void updateEditorText(@NotNull StudyEditor editor, @NotNull TaskFile newTaskFile) { - ApplicationManager.getApplication().invokeLater(() -> ApplicationManager.getApplication().runWriteAction(() -> { - final Document document = editor.getEditor().getDocument(); - document.setText(newTaskFile.text); - })); - } - - private static void setTaskFileParameters(@NotNull StudyEditor editor, @NotNull Task task, @NotNull TaskFile newTaskFile) { - TaskFile currentTaskFile = editor.getTaskFile(); - currentTaskFile.text = newTaskFile.text; - currentTaskFile.name = newTaskFile.name; - currentTaskFile.setTask(task); - task.getTaskFiles().clear(); - task.taskFiles.put(CODE_TASK_NAME, currentTaskFile); + taskDir.delete(EduAdaptiveStepicConnector.class); } private static void setToolWindowText(@NotNull Project project, @NotNull Task task) { From 982bae514c14c4464a17c4c5f4e4ec62ea646fc7 Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Fri, 7 Apr 2017 18:22:40 +0300 Subject: [PATCH 075/111] Pass lesson to addNextRecommendation method instead of getting lesson from current editor --- .../edu/learning/checker/StudyCheckTask.java | 6 ++++-- .../learning/stepic/EduAdaptiveStepicConnector.java | 12 +++++------- .../stepic/StepicAdaptiveReactionsPanel.java | 3 ++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java index 0c070df1cb99..2db45eeb83e3 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java @@ -173,7 +173,8 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun if (reactionPosted) { if (myStatusBeforeCheck != StudyStatus.Solved) { myTask.setStatus(StudyStatus.Solved); - EduAdaptiveStepicConnector.addNextRecommendedTask(myProject, indicator, EduAdaptiveStepicConnector.NEXT_RECOMMENDATION_REACTION); + EduAdaptiveStepicConnector.addNextRecommendedTask(myProject, myTask.getLesson(), indicator, + EduAdaptiveStepicConnector.NEXT_RECOMMENDATION_REACTION); } } else { @@ -203,7 +204,8 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun if (pair.getFirst()) { onTaskSolved("Congratulations! Remote tests passed."); if (myStatusBeforeCheck != StudyStatus.Solved) { - EduAdaptiveStepicConnector.addNextRecommendedTask(myProject, indicator, EduAdaptiveStepicConnector.NEXT_RECOMMENDATION_REACTION); + EduAdaptiveStepicConnector.addNextRecommendedTask(myProject, myTask.getLesson(), indicator, + EduAdaptiveStepicConnector.NEXT_RECOMMENDATION_REACTION); } } else { diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java index c8af73b7b3c8..accecb8ad225 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java @@ -26,7 +26,6 @@ import com.jetbrains.edu.learning.courseFormat.tasks.CodeTask; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import com.jetbrains.edu.learning.courseFormat.tasks.TheoryTask; import com.jetbrains.edu.learning.courseGeneration.StudyGenerator; -import com.jetbrains.edu.learning.editor.StudyEditor; import com.jetbrains.edu.learning.navigation.StudyNavigator; import com.jetbrains.edu.learning.ui.StudyToolWindow; import org.apache.http.HttpEntity; @@ -281,12 +280,12 @@ public class EduAdaptiveStepicConnector { } } - public static void addNextRecommendedTask(@NotNull Project project, @NotNull ProgressIndicator indicator, int reactionToPost) { - final StudyEditor editor = StudyUtils.getSelectedStudyEditor(project); + public static void addNextRecommendedTask(@NotNull Project project, + @NotNull Lesson lesson, + @NotNull ProgressIndicator indicator, + int reactionToPost) { final Course course = StudyTaskManager.getInstance(project).getCourse(); - Task selectedTask = StudyUtils.getTaskFromSelectedEditor(project); - if (editor == null || editor.getTaskFile() == null || selectedTask == null || selectedTask.getLesson() == null || - !(course instanceof RemoteCourse)) { + if (!(course instanceof RemoteCourse)) { LOG.warn("Course is in incorrect state"); ApplicationManager.getApplication().invokeLater(() -> StudyUtils.showErrorPopupOnToolbar(project, "Can't get next recommendation: course is broken")); @@ -302,7 +301,6 @@ public class EduAdaptiveStepicConnector { return; } - final Lesson lesson = selectedTask.getLesson(); final boolean reactionPosted = postRecommendationReaction(String.valueOf(lesson.getId()), String.valueOf(user.getId()), reactionToPost); if (!reactionPosted) { LOG.warn("Recommendation reaction wasn't posted"); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicAdaptiveReactionsPanel.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicAdaptiveReactionsPanel.java index 6f68839fd936..8aabf57e7144 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicAdaptiveReactionsPanel.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicAdaptiveReactionsPanel.java @@ -148,7 +148,8 @@ public class StepicAdaptiveReactionsPanel extends JPanel { public void run(@NotNull ProgressIndicator indicator) { StepicAdaptiveReactionsPanel.this.setEnabledRecursive(false); ApplicationManager.getApplication().invokeLater(()->setBackground(UIUtil.getLabelBackground())); - EduAdaptiveStepicConnector.addNextRecommendedTask(StepicAdaptiveReactionsPanel.this.myProject, indicator, myReaction); + EduAdaptiveStepicConnector.addNextRecommendedTask(StepicAdaptiveReactionsPanel.this.myProject, task.getLesson(), indicator, + myReaction); StepicAdaptiveReactionsPanel.this.setEnabledRecursive(true); } }); From a728f7e878f083ea0254b2b2bed80668a6d8557e Mon Sep 17 00:00:00 2001 From: Anton Tarasov Date: Fri, 7 Apr 2017 18:38:29 +0300 Subject: [PATCH 076/111] IDEA-171160 [macos] progress indicator in AppIcon consumes CPU --- platform/platform-impl/src/com/intellij/ui/AppIcon.java | 7 ++++++- 1 file changed, 6 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 8f2c55088eb9..d80edacb8662 100644 --- a/platform/platform-impl/src/com/intellij/ui/AppIcon.java +++ b/platform/platform-impl/src/com/intellij/ui/AppIcon.java @@ -27,6 +27,7 @@ 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.containers.HashMap; import com.intellij.util.ui.ImageUtil; import com.intellij.util.ui.UIUtil; import org.apache.sanselan.ImageWriteException; @@ -46,6 +47,7 @@ import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Map; public abstract class AppIcon { private static final Logger LOG = Logger.getInstance(AppIcon.class); @@ -165,6 +167,7 @@ public abstract class AppIcon { @SuppressWarnings("UseJBColor") private static class MacAppIcon extends BaseIcon { private BufferedImage myAppImage; + private Map myProgressImagesCache = new HashMap<>(); private BufferedImage getAppImage() { assertIsDispatchThread(); @@ -240,6 +243,7 @@ public abstract class AppIcon { if (myCurrentProcessId != null && !myCurrentProcessId.equals(processId)) return false; setDockIcon(getAppImage()); + myProgressImagesCache.remove(myCurrentProcessId); myCurrentProcessId = null; myLastValue = 0; @@ -308,7 +312,8 @@ public abstract class AppIcon { progressArea.intersect(borderArea); - AppImage appImg = createAppImage(); + AppImage appImg = myProgressImagesCache.get(myCurrentProcessId); + if (appImg == null) myProgressImagesCache.put(myCurrentProcessId, appImg = createAppImage()); appImg.myG2d.setColor(PROGRESS_BACKGROUND_COLOR); appImg.myG2d.fill(backgroundArea); From ea76b1499c97c4ceb89ff695bda6a9c40d688c0c Mon Sep 17 00:00:00 2001 From: Valentina Kiryushkina Date: Fri, 7 Apr 2017 18:52:46 +0300 Subject: [PATCH 077/111] Fix course creator mode check --- .../src/com/jetbrains/edu/coursecreator/CCProjectComponent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java index 94573e76c17c..d1548a4244fe 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/CCProjectComponent.java @@ -104,8 +104,8 @@ public class CCProjectComponent extends AbstractProjectComponent { } public void projectOpened() { + migrateIfNeeded(); if (CCUtils.isCourseCreator(myProject)) { - migrateIfNeeded(); VirtualFileManager.getInstance().addVirtualFileListener(myTaskFileLifeListener); EduUsagesCollector.projectTypeOpened(CCUtils.COURSE_MODE); } From 8e598aa9086a77127de81205d2aa834fe53c2450 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 7 Apr 2017 15:35:35 +0200 Subject: [PATCH 078/111] java 9: reject private modifiers in annotation types (IDEA-171088) --- .../codeInsight/daemon/impl/analysis/HighlightUtil.java | 2 +- .../advHighlighting9/PrivateInInterfaces.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 467f71c2a18d..f7befda24842 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -967,7 +967,7 @@ public class HighlightUtil extends HighlightUtilBase { if (PsiModifier.PRIVATE.equals(modifier)) { isAllowed &= modifierOwnerParent instanceof PsiClass && - (!((PsiClass)modifierOwnerParent).isInterface() || PsiUtil.isLanguageLevel9OrHigher(modifierOwner)); + (!((PsiClass)modifierOwnerParent).isInterface() || PsiUtil.isLanguageLevel9OrHigher(modifierOwner) && !((PsiClass)modifierOwnerParent).isAnnotationType()); } else if (PsiModifier.STRICTFP.equals(modifier)) { isAllowed &= modifierOwnerParent instanceof PsiClass && (!((PsiClass)modifierOwnerParent).isInterface() || PsiUtil.isLanguageLevel8OrHigher(modifierOwner)); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting9/PrivateInInterfaces.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting9/PrivateInInterfaces.java index 4998dae837eb..d0f2e08ea6ba 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting9/PrivateInInterfaces.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting9/PrivateInInterfaces.java @@ -20,4 +20,9 @@ interface E { interface F { private int m = 0; +} + +@interface G { + private String m(); + private String m1() {return "";} } \ No newline at end of file From 229ff01656383258024e805580939b3ce1f7da69 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 7 Apr 2017 15:51:35 +0200 Subject: [PATCH 079/111] java 9: ensure private methods in interfaces do not receive implicit public modifier (IDEA-171089) --- .../psi/impl/source/PsiModifierListImpl.java | 9 ++++--- .../PrivateInInterfacesOverriding.java | 25 +++++++++++++++++++ .../daemon/LightAdvHighlightingJdk9Test.java | 1 + 3 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting9/PrivateInInterfacesOverriding.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java index 27b21d3ac3b5..5a1b21416507 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiModifierListImpl.java @@ -17,7 +17,6 @@ package com.intellij.psi.impl.source; import com.intellij.codeInsight.AnnotationTargetUtil; import com.intellij.lang.ASTNode; -import com.intellij.openapi.util.Condition; import com.intellij.psi.*; import com.intellij.psi.augment.PsiAugmentProvider; import com.intellij.psi.impl.CheckUtil; @@ -158,9 +157,11 @@ public class PsiModifierListImpl extends JavaStubPsiElement else if (parent instanceof PsiMethod) { PsiClass aClass = ((PsiMethod)parent).getContainingClass(); if (aClass != null && aClass.isInterface()) { - implicitModifiers.add(PUBLIC); - if (!explicitModifiers.contains(DEFAULT) && !explicitModifiers.contains(STATIC) && !explicitModifiers.contains(PRIVATE)) { - implicitModifiers.add(ABSTRACT); + if (!explicitModifiers.contains(PRIVATE)) { + implicitModifiers.add(PUBLIC); + if (!explicitModifiers.contains(DEFAULT) && !explicitModifiers.contains(STATIC)) { + implicitModifiers.add(ABSTRACT); + } } } else if (aClass != null && aClass.isEnum() && ((PsiMethod)parent).isConstructor()) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting9/PrivateInInterfacesOverriding.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting9/PrivateInInterfacesOverriding.java new file mode 100644 index 000000000000..091b779ac2a6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting9/PrivateInInterfacesOverriding.java @@ -0,0 +1,25 @@ +interface A { + void m(); +} +interface A1 extends A { + private static void m() {} +} +interface A2 extends A { + private void m() {} +} + +interface B { + private void m() {} +} +interface B1 extends B { + private void m() {} +} +interface B2 extends B { + private static void m() {} +} +interface B3 extends B { + default void m() {} +} +interface B4 extends B { + void m(); +} diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk9Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk9Test.java index c4b9a08f1e0a..f23c916d42e6 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk9Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk9Test.java @@ -41,6 +41,7 @@ public class LightAdvHighlightingJdk9Test extends LightDaemonAnalyzerTestCase { public void testSafeVarargsApplicability() { doTest(true, false); } public void testPrivateInInterfaces() { doTest(false, false); } + public void testPrivateInInterfacesOverriding() { doTest(false, false); } public void testUnderscore() { doTest(false, false); } public void testTryWithResources() { doTest(false, false); } From 32073ed7f90fe6d34edea958d2ebe2de2cd69772 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 7 Apr 2017 16:39:02 +0200 Subject: [PATCH 080/111] java 9: hide inappropriate for interface modifier suggestions, ensure valid combination of modifiers (IDEA-171091) --- .../daemon/impl/analysis/HighlightUtil.java | 5 +++ .../daemon/impl/quickfix/ModifierFix.java | 20 ++++++++--- .../quickFix/modifier19/afterMakeDefault.java | 10 ++++++ .../modifier19/beforeMakeDefault.java | 10 ++++++ .../daemon/quickFix/Modifier19Test.java | 35 +++++++++++++++++++ 5 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier19/afterMakeDefault.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier19/beforeMakeDefault.java create mode 100644 java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/Modifier19Test.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index f7befda24842..edaf4e6391c8 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -200,6 +200,7 @@ public class HighlightUtil extends HighlightUtilBase { /** * make element protected/package-private/public suggestion + * for private method in the interface it should add default modifier as well */ static void registerAccessQuickFixAction(@NotNull PsiMember refElement, @NotNull PsiJavaCodeReferenceElement place, @@ -238,6 +239,10 @@ public class HighlightUtil extends HighlightUtilBase { if (refElement.hasModifierProperty(PsiModifier.PROTECTED)) { minModifier = PsiModifier.PUBLIC; } + PsiClass containingClass = refElement.getContainingClass(); + if (containingClass != null && containingClass.isInterface()) { + minModifier = PsiModifier.PUBLIC; + } String[] modifiers = {PsiModifier.PACKAGE_LOCAL, PsiModifier.PROTECTED, PsiModifier.PUBLIC,}; for (int i = ArrayUtil.indexOf(modifiers, minModifier); i < modifiers.length; i++) { @PsiModifier.ModifierConstant String modifier = modifiers[i]; diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java index 3f3948ce123c..068000712f53 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ModifierFix.java @@ -200,11 +200,21 @@ public class ModifierFix extends LocalQuickFixAndIntentionActionOnPsiElement { ApplicationManager.getApplication().runWriteAction(() -> { changeModifierList(modifierList); - if (myShouldHave && owner instanceof PsiMethod && PsiModifier.ABSTRACT.equals(myModifier)) { - final PsiMethod method = (PsiMethod)owner; - final PsiClass aClass = method.getContainingClass(); - if (aClass != null && !aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { - changeModifierList(aClass.getModifierList()); + if (myShouldHave && owner instanceof PsiMethod) { + if (PsiModifier.ABSTRACT.equals(myModifier)) { + final PsiMethod method = (PsiMethod)owner; + final PsiClass aClass = method.getContainingClass(); + if (aClass != null && !aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + changeModifierList(aClass.getModifierList()); + } + } + else if (PsiModifier.PUBLIC.equals(myModifier) && + ((PsiMethod)owner).getBody() != null && + !((PsiMethod)owner).hasModifierProperty(PsiModifier.STATIC)) { + PsiClass containingClass = ((PsiMethod)owner).getContainingClass(); + if (containingClass != null && containingClass.isInterface()) { + modifierList.setModifierProperty(PsiModifier.DEFAULT, true); + } } } UndoUtil.markPsiFileForUndo(containingFile); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier19/afterMakeDefault.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier19/afterMakeDefault.java new file mode 100644 index 000000000000..c787af2ad7ee --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier19/afterMakeDefault.java @@ -0,0 +1,10 @@ +// "Make 'I.foo' public" "true" +interface I { + default void foo() { } +} + +class A implements I { + { + this.foo(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier19/beforeMakeDefault.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier19/beforeMakeDefault.java new file mode 100644 index 000000000000..76b1c34ebdb9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/modifier19/beforeMakeDefault.java @@ -0,0 +1,10 @@ +// "Make 'I.foo' public" "true" +interface I { + private void foo() { } +} + +class A implements I { + { + this.foo(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/Modifier19Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/Modifier19Test.java new file mode 100644 index 000000000000..202de7565669 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/Modifier19Test.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2013 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.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import org.jetbrains.annotations.NotNull; + +public class Modifier19Test extends LightQuickFixParameterizedTestCase { + public void test() throws Exception { doAllTests(); } + + @Override + protected String getBasePath() { + return "/codeInsight/daemonCodeAnalyzer/quickFix/modifier19"; + } + + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return LightCodeInsightFixtureTestCase.JAVA_9; + } +} From c0b06a8f2a8b5414e43b0cf950d5158ee98dcbd1 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 7 Apr 2017 18:15:44 +0200 Subject: [PATCH 081/111] java 8: access static method through instance variable: don't show warning, error is enough; add quick fix for an error same as for inspection --- .../codeInsight/intention/QuickFixFactory.java | 3 +++ .../impl/analysis/HighlightMethodUtil.java | 17 ++++++++--------- .../intention/EmptyQuickFixFactory.java | 7 +++++++ .../AccessStaticViaInstanceBase.java | 4 ++++ .../quickfix/AccessStaticViaInstanceFix.java | 2 +- .../impl/config/QuickFixFactoryImpl.java | 7 +++++++ .../afterAccessForStaticMethodInInterface.java | 10 ++++++++++ .../beforeAccessForStaticMethodInInterface.java | 10 ++++++++++ 8 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/accessStaticViaInstance/afterAccessForStaticMethodInInterface.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/accessStaticViaInstance/beforeAccessForStaticMethodInInterface.java diff --git a/java/java-analysis-api/src/com/intellij/codeInsight/intention/QuickFixFactory.java b/java/java-analysis-api/src/com/intellij/codeInsight/intention/QuickFixFactory.java index 59149f132d9d..a89bc6392904 100644 --- a/java/java-analysis-api/src/com/intellij/codeInsight/intention/QuickFixFactory.java +++ b/java/java-analysis-api/src/com/intellij/codeInsight/intention/QuickFixFactory.java @@ -291,6 +291,9 @@ public abstract class QuickFixFactory { @NotNull public abstract IntentionAction createInsertMethodCallFix(@NotNull PsiMethodCallExpression call, PsiMethod method); + @NotNull + public abstract LocalQuickFixAndIntentionActionOnPsiElement createAccessStaticViaInstanceFix(PsiReferenceExpression methodRef, JavaResolveResult result); + @NotNull public abstract IntentionAction createWrapStringWithFileFix(@Nullable PsiType type, @NotNull PsiExpression expression); } \ No newline at end of file diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 5b4b97d96ecf..654dedd48022 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -657,33 +657,32 @@ public class HighlightMethodUtil { return null; } String description; - PsiElement elementToHighlight; + PsiElement elementToHighlight = ObjectUtils.notNull(referenceToMethod.getReferenceNameElement(), referenceToMethod); if (element != null && !resolveResult.isAccessible()) { description = HighlightUtil.buildProblemWithAccessDescription(referenceToMethod, resolveResult); - elementToHighlight = referenceToMethod.getReferenceNameElement(); } else if (element != null && !resolveResult.isStaticsScopeCorrect()) { - description = null; - elementToHighlight = ObjectUtils.notNull(referenceToMethod.getReferenceNameElement(), referenceToMethod); - if (element instanceof PsiMethod && ((PsiMethod)element).hasModifierProperty(PsiModifier.STATIC)) { PsiClass containingClass = ((PsiMethod)element).getContainingClass(); if (containingClass != null && containingClass.isInterface()) { HighlightInfo info = HighlightUtil.checkFeature(elementToHighlight, HighlightUtil.Feature.STATIC_INTERFACE_CALLS, languageLevel, file); if (info != null) return info; description = checkStaticInterfaceMethodCallQualifier(referenceToMethod, resolveResult.getCurrentFileResolveScope(), containingClass); + if (description != null) { + HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(highlightInfoType).range(elementToHighlight).description(description) + .escapedToolTip(XmlStringUtil.escapeString(description)).create(); + QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createAccessStaticViaInstanceFix(referenceToMethod, resolveResult)); + return highlightInfo; + } } } - if (description == null) { - description = HighlightUtil.buildProblemWithStaticDescription(element); - } + description = HighlightUtil.buildProblemWithStaticDescription(element); } else { String methodName = referenceToMethod.getReferenceName() + buildArgTypesList(list); description = JavaErrorMessages.message("cannot.resolve.method", methodName); if (candidates.length == 0) { - elementToHighlight = referenceToMethod.getReferenceNameElement(); highlightInfoType = HighlightInfoType.WRONG_REF; } else { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/EmptyQuickFixFactory.java b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/EmptyQuickFixFactory.java index 7fe3c51a17c5..b3544def540e 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/intention/EmptyQuickFixFactory.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/intention/EmptyQuickFixFactory.java @@ -669,6 +669,13 @@ public class EmptyQuickFixFactory extends QuickFixFactory { return QuickFixes.EMPTY_FIX; } + @NotNull + @Override + public LocalQuickFixAndIntentionActionOnPsiElement createAccessStaticViaInstanceFix(PsiReferenceExpression methodRef, + JavaResolveResult result) { + return QuickFixes.EMPTY_FIX; + } + @NotNull @Override public IntentionAction createWrapStringWithFileFix(@Nullable PsiType type, @NotNull PsiExpression expression) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/accessStaticViaInstance/AccessStaticViaInstanceBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/accessStaticViaInstance/AccessStaticViaInstanceBase.java index 748bce25fc53..a1addd4f5ae4 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/accessStaticViaInstance/AccessStaticViaInstanceBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/accessStaticViaInstance/AccessStaticViaInstanceBase.java @@ -84,6 +84,10 @@ public class AccessStaticViaInstanceBase extends BaseJavaBatchLocalInspectionToo } if (!((PsiMember)resolved).hasModifierProperty(PsiModifier.STATIC)) return; + //don't report warnings on compilation errors + PsiClass containingClass = ((PsiMember)resolved).getContainingClass(); + if (containingClass != null && containingClass.isInterface()) return; + String description = JavaErrorMessages.message("static.member.accessed.via.instance.reference", JavaHighlightUtil.formatType(qualifierExpression.getType()), HighlightMessageUtil.getSymbolName(resolved, result.getSubstitutor())); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AccessStaticViaInstanceFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AccessStaticViaInstanceFix.java index d41e92b9522c..78b9445ec247 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AccessStaticViaInstanceFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AccessStaticViaInstanceFix.java @@ -96,7 +96,7 @@ public class AccessStaticViaInstanceFix extends LocalQuickFixAndIntentionActionO try { PsiElement newQualifier = qualifierExpression.replace(factory.createReferenceExpression(containingClass)); PsiElement qualifiedWithClassName = myExpression.copy(); - if (myExpression.getTypeParameters().length == 0) { + if (myExpression.getTypeParameters().length == 0 && !(containingClass.isInterface() && !containingClass.equals(PsiTreeUtil.getParentOfType(myExpression, PsiClass.class)))) { newQualifier.delete(); if (myExpression.resolve() != myMember) { myExpression.replace(qualifiedWithClassName); diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java index 93ec1bfd0293..50992a935694 100644 --- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/config/QuickFixFactoryImpl.java @@ -851,6 +851,13 @@ public class QuickFixFactoryImpl extends QuickFixFactory { return new InsertMethodCallFix(call, method); } + @NotNull + @Override + public LocalQuickFixAndIntentionActionOnPsiElement createAccessStaticViaInstanceFix(PsiReferenceExpression methodRef, + JavaResolveResult result) { + return new AccessStaticViaInstanceFix(methodRef, result, true); + } + @NotNull @Override public IntentionAction createWrapStringWithFileFix(@Nullable PsiType type, @NotNull PsiExpression expression) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/accessStaticViaInstance/afterAccessForStaticMethodInInterface.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/accessStaticViaInstance/afterAccessForStaticMethodInInterface.java new file mode 100644 index 000000000000..19861c850d9e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/accessStaticViaInstance/afterAccessForStaticMethodInInterface.java @@ -0,0 +1,10 @@ +// "Access static 'I.m()' via class 'I' reference" "true" +interface I { + static void m() {} +} + +class A implements I { + { + I.m(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/accessStaticViaInstance/beforeAccessForStaticMethodInInterface.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/accessStaticViaInstance/beforeAccessForStaticMethodInInterface.java new file mode 100644 index 000000000000..26a1b58499c2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/accessStaticViaInstance/beforeAccessForStaticMethodInInterface.java @@ -0,0 +1,10 @@ +// "Access static 'I.m()' via class 'I' reference" "true" +interface I { + static void m() {} +} + +class A implements I { + { + this.m(); + } +} \ No newline at end of file From c11a485d35d878f43bb971f08b9f2ee76d2e5617 Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Fri, 7 Apr 2017 19:28:30 +0300 Subject: [PATCH 082/111] Fix Debug Console when attaching to IPython process (PY-20531) --- .../pydev/_pydev_bundle/pydev_ipython_console_011.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/python/helpers/pydev/_pydev_bundle/pydev_ipython_console_011.py b/python/helpers/pydev/_pydev_bundle/pydev_ipython_console_011.py index 7745c7b60549..b7705c6f680d 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_ipython_console_011.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_ipython_console_011.py @@ -313,16 +313,17 @@ class _PyDevFrontEnd: version = release.__version__ def __init__(self, show_banner=True): - # Create and initialize our IPython instance. - self.ipython = PyDevTerminalInteractiveShell.instance() + if hasattr(PyDevTerminalInteractiveShell, '_instance') and PyDevTerminalInteractiveShell._instance is not None: + self.ipython = PyDevTerminalInteractiveShell._instance + else: + self.ipython = PyDevTerminalInteractiveShell.instance() if show_banner: # Display the IPython banner, this has version info and # help info self.ipython.show_banner() - self._curr_exec_line = 0 self._curr_exec_lines = [] From 6d5b53535c9d1b6c5cf3a587a09fba8c9db8510b Mon Sep 17 00:00:00 2001 From: "Liana.Bakradze" Date: Fri, 7 Apr 2017 13:55:29 +0300 Subject: [PATCH 083/111] EDU-904 Do not run file before check in Edu Python --- .../edu/learning/checker/StudyCheckTask.java | 16 ---------------- .../fileTemplates/internal/test_helper.py.ft | 7 ------- 2 files changed, 23 deletions(-) diff --git a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java index 2db45eeb83e3..55e82678ab00 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java @@ -3,7 +3,6 @@ package com.jetbrains.edu.learning.checker; import com.intellij.execution.process.CapturingProcessHandler; import com.intellij.execution.process.ProcessOutput; import com.intellij.ide.projectView.ProjectView; -import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -16,7 +15,6 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.jetbrains.edu.learning.*; -import com.jetbrains.edu.learning.actions.StudyRunAction; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; @@ -47,9 +45,7 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun private final Ref myCheckInProcess; private final Process myTestProcess; private final String myCommandLine; - private boolean myRunTestFile = true; private static final String FAILED_CHECK_LAUNCH = "Failed to launch checking"; - private static final String DO_NOT_RUN_ON_CHECK = "DO_NOT_RUN_ON_CHECK"; public StudyCheckTask(Project project, StudyState studyState, Ref checkInProcess, Process testProcess, String commandLine) { super(project, "Checking Task"); @@ -98,9 +94,6 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun private void checkForEduCourse(@NotNull ProgressIndicator indicator) { final StudyTestsOutputParser.TestsOutput testsOutput = getTestOutput(indicator); - if (myRunTestFile) { - ApplicationManager.getApplication().invokeLater(() -> runTask(myProject)); - } if (testsOutput != null) { if (testsOutput.isSuccess()) { onTaskSolved(testsOutput.getMessage()); @@ -119,14 +112,6 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun } } - private static void runTask(@NotNull Project project) { - final StudyRunAction runAction = (StudyRunAction)ActionManager.getInstance().getAction(StudyRunAction.ACTION_ID); - if (runAction == null) { - return; - } - runAction.run(project); - } - @Nullable private StudyTestsOutputParser.TestsOutput getTestOutput(@NotNull ProgressIndicator indicator) { final CapturingProcessHandler handler = new CapturingProcessHandler(myTestProcess, null, myCommandLine); @@ -135,7 +120,6 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun ApplicationManager.getApplication().invokeLater( () -> StudyCheckUtils.showTestResultPopUp("Check cancelled", MessageType.WARNING.getPopupBackground(), myProject)); } - myRunTestFile = !output.getStdout().contains(DO_NOT_RUN_ON_CHECK); final Course course = StudyTaskManager.getInstance(myProject).getCourse(); if (course != null) { final StudyTestsOutputParser.TestsOutput testsOutput = StudyTestsOutputParser.getTestsOutput(output, course.isAdaptive()); diff --git a/python/educational-python/resources/fileTemplates/internal/test_helper.py.ft b/python/educational-python/resources/fileTemplates/internal/test_helper.py.ft index 42bdaa245c70..16ba2d37f90c 100644 --- a/python/educational-python/resources/fileTemplates/internal/test_helper.py.ft +++ b/python/educational-python/resources/fileTemplates/internal/test_helper.py.ft @@ -218,13 +218,6 @@ def check_samples(samples=()): passed() -def do_not_run_on_check(): - """ - Do not execute task file on check - """ - print("#educational_plugin DO_NOT_RUN_ON_CHECK") - - def run_common_tests(error_text="Please, reload file and try again"): test_is_not_empty() test_answer_placeholders_text_deleted() From 6fb957d677647c88a8ea1b923cacc292c7a9d24c Mon Sep 17 00:00:00 2001 From: "Liana.Bakradze" Date: Fri, 7 Apr 2017 14:06:09 +0300 Subject: [PATCH 084/111] EDU-881 Remove StudyExecutor --- .../resources/META-INF/plugin.xml | 5 - .../edu/learning/EduPluginConfigurator.java | 1 - .../jetbrains/edu/learning/StudyUtils.java | 43 ------ .../edu/learning/actions/StudyRunAction.java | 123 ------------------ .../edu/learning/checker/StudyExecutor.java | 46 ------- .../stepic/EduAdaptiveStepicConnector.java | 12 +- .../Edu-Python/resources/META-INF/plugin.xml | 1 - .../edu/learning/PyStudyCheckAction.java | 2 +- .../edu/learning/PyStudyExecutor.java | 96 -------------- 9 files changed, 6 insertions(+), 323 deletions(-) delete mode 100644 python/educational-core/src/com/jetbrains/edu/learning/actions/StudyRunAction.java delete mode 100644 python/educational-core/src/com/jetbrains/edu/learning/checker/StudyExecutor.java delete mode 100644 python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyExecutor.java diff --git a/python/educational-core/resources/META-INF/plugin.xml b/python/educational-core/resources/META-INF/plugin.xml index dcbc35a025d4..aebea6fd6a7c 100644 --- a/python/educational-core/resources/META-INF/plugin.xml +++ b/python/educational-core/resources/META-INF/plugin.xml @@ -41,9 +41,6 @@ - - - @@ -77,8 +74,6 @@ description="Watch test input "/> - diff --git a/python/educational-core/src/com/jetbrains/edu/learning/EduPluginConfigurator.java b/python/educational-core/src/com/jetbrains/edu/learning/EduPluginConfigurator.java index aaa21bbf5ead..c41739bef591 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/EduPluginConfigurator.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/EduPluginConfigurator.java @@ -105,7 +105,6 @@ public interface EduPluginConfigurator { } group.add(action); } - group.add(new StudyRunAction()); group.add(new StudyEditInputAction()); return group; } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/src/com/jetbrains/edu/learning/StudyUtils.java index 8909c6936fd7..c12b44757ee6 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/StudyUtils.java @@ -1,15 +1,11 @@ package com.jetbrains.edu.learning; -import com.intellij.execution.RunContentExecutor; -import com.intellij.execution.configurations.GeneralCommandLine; -import com.intellij.execution.process.ProcessHandler; import com.intellij.ide.IdeView; import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.fileTemplates.FileTemplateUtil; import com.intellij.ide.projectView.ProjectView; import com.intellij.ide.util.EditorHelper; -import com.intellij.lang.Language; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; @@ -31,7 +27,6 @@ import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; import com.intellij.openapi.fileEditor.impl.LoadTextUtil; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.JBPopupFactory; @@ -61,8 +56,6 @@ import com.intellij.util.TimeoutUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.MarkdownUtil; import com.intellij.util.ui.UIUtil; -import com.jetbrains.edu.learning.checker.StudyExecutor; -import com.jetbrains.edu.learning.checker.StudyTestRunner; import com.jetbrains.edu.learning.core.EduAnswerPlaceholderDeleteHandler; import com.jetbrains.edu.learning.core.EduAnswerPlaceholderPainter; import com.jetbrains.edu.learning.core.EduNames; @@ -237,42 +230,6 @@ public class StudyUtils { } } - @Nullable - public static Sdk findSdk(@NotNull final Task task, @NotNull final Project project) { - final Language language = task.getLesson().getCourse().getLanguageById(); - return StudyExecutor.INSTANCE.forLanguage(language).findSdk(project); - } - - @NotNull - public static StudyTestRunner getTestRunner(@NotNull final Task task, @NotNull final VirtualFile taskDir) { - final Language language = task.getLesson().getCourse().getLanguageById(); - return StudyExecutor.INSTANCE.forLanguage(language).getTestRunner(task, taskDir); - } - - public static RunContentExecutor getExecutor(@NotNull final Project project, @NotNull final Task currentTask, - @NotNull final ProcessHandler handler) { - final Language language = currentTask.getLesson().getCourse().getLanguageById(); - return StudyExecutor.INSTANCE.forLanguage(language).getExecutor(project, handler); - } - - public static void setCommandLineParameters(@NotNull final GeneralCommandLine cmd, - @NotNull final Project project, - @NotNull final String filePath, - @NotNull final String sdkPath, - @NotNull final Task currentTask) { - final Language language = currentTask.getLesson().getCourse().getLanguageById(); - StudyExecutor.INSTANCE.forLanguage(language).setCommandLineParameters(cmd, project, filePath, sdkPath, currentTask); - } - - public static void showNoSdkNotification(@NotNull final Task currentTask, @NotNull final Project project) { - final Lesson lesson = currentTask.getLesson(); - if (lesson == null) return; - final Course course = lesson.getCourse(); - if (course == null) return; - final Language language = course.getLanguageById(); - StudyExecutor.INSTANCE.forLanguage(language).showNoSdkNotification(project); - } - /** * shows pop up in the center of "check task" button in study editor diff --git a/python/educational-core/src/com/jetbrains/edu/learning/actions/StudyRunAction.java b/python/educational-core/src/com/jetbrains/edu/learning/actions/StudyRunAction.java deleted file mode 100644 index a565dadd4528..000000000000 --- a/python/educational-core/src/com/jetbrains/edu/learning/actions/StudyRunAction.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.jetbrains.edu.learning.actions; - -import com.intellij.execution.ExecutionException; -import com.intellij.execution.RunContentExecutor; -import com.intellij.execution.configurations.GeneralCommandLine; -import com.intellij.execution.process.OSProcessHandler; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.execution.process.ProcessListener; -import com.intellij.icons.AllIcons; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.vfs.VirtualFile; -import com.jetbrains.edu.learning.core.EduUtils; -import com.jetbrains.edu.learning.courseFormat.tasks.Task; -import com.jetbrains.edu.learning.courseFormat.TaskFile; -import com.jetbrains.edu.learning.StudyTaskManager; -import com.jetbrains.edu.learning.StudyUtils; -import com.jetbrains.edu.learning.courseFormat.UserTest; -import com.jetbrains.edu.learning.editor.StudyEditor; -import org.jetbrains.annotations.NotNull; - -import java.util.LinkedList; -import java.util.List; - -public class StudyRunAction extends DumbAwareAction { - private static final Logger LOG = Logger.getInstance(StudyRunAction.class.getName()); - public static final String ACTION_ID = "StudyRunAction"; - private ProcessHandler myHandler; - private List myProcessListeners = new LinkedList<>(); - - public StudyRunAction() { - super("Run File With Tests", "Run your code with tests", AllIcons.General.Run); - } - - public void run(@NotNull final Project project) { - if (myHandler != null && !myHandler.isProcessTerminated()) return; - Editor selectedEditor = StudyUtils.getSelectedEditor(project); - FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); - assert selectedEditor != null; - VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument()); - - if (openedFile != null && openedFile.getCanonicalPath() != null) { - String filePath = openedFile.getCanonicalPath(); - executeFile(project, openedFile, filePath); - } - } - - private void executeFile(@NotNull final Project project, - @NotNull final VirtualFile openedFile, @NotNull final String filePath) { - GeneralCommandLine cmd = new GeneralCommandLine(); - cmd.withWorkDirectory(openedFile.getParent().getCanonicalPath()); - - TaskFile selectedTaskFile = StudyUtils.getTaskFile(project, openedFile); - assert selectedTaskFile != null; - final Task currentTask = selectedTaskFile.getTask(); - final Sdk sdk = StudyUtils.findSdk(currentTask, project); - if (sdk == null) { - StudyUtils.showNoSdkNotification(currentTask, project); - return; - } - String sdkHomePath = sdk.getHomePath(); - if (sdkHomePath != null) { - cmd.setExePath(sdkHomePath); - StudyUtils.setCommandLineParameters(cmd, project, filePath, sdkHomePath, currentTask); - - try { - myHandler = new OSProcessHandler(cmd); - } - catch (ExecutionException e) { - LOG.error(e); - return; - } - - for (ProcessListener processListener : myProcessListeners) { - myHandler.addProcessListener(processListener); - } - - final RunContentExecutor executor = StudyUtils.getExecutor(project, currentTask, myHandler); - if (executor != null) { - Disposer.register(project, executor); - executor.run(); - } - EduUtils.synchronize(); - } - } - - public void addProcessListener(@NotNull final ProcessListener processListener) { - myProcessListeners.add(processListener); - } - - public void removeProcessListener(@NotNull final ProcessListener processListener) { - myProcessListeners.remove(processListener); - } - - public void actionPerformed(@NotNull AnActionEvent e) { - final Project project = e.getProject(); - if (project != null) { - run(project); - } - } - - @Override - public void update(AnActionEvent e) { - EduUtils.enableAction(e, false); - - final Project project = e.getProject(); - if (project != null) { - StudyEditor studyEditor = StudyUtils.getSelectedStudyEditor(project); - if (studyEditor != null) { - final List userTests = StudyTaskManager.getInstance(project).getUserTests(studyEditor.getTaskFile().getTask()); - if (!userTests.isEmpty()) { - EduUtils.enableAction(e, true); - } - } - } - } -} diff --git a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyExecutor.java b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyExecutor.java deleted file mode 100644 index 8e27c2bedd79..000000000000 --- a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyExecutor.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2000-2014 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.jetbrains.edu.learning.checker; - -import com.intellij.execution.RunContentExecutor; -import com.intellij.execution.configurations.GeneralCommandLine; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.lang.LanguageExtension; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.vfs.VirtualFile; -import com.jetbrains.edu.learning.courseFormat.tasks.Task; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public interface StudyExecutor { - LanguageExtension INSTANCE = new LanguageExtension<>("Edu.StudyExecutor"); - - @Nullable - Sdk findSdk(@NotNull final Project project); - - StudyTestRunner getTestRunner(@NotNull final Task task, @NotNull final VirtualFile taskDir); - - RunContentExecutor getExecutor(@NotNull final Project project, @NotNull final ProcessHandler handler); - - void setCommandLineParameters(@NotNull final GeneralCommandLine cmd, - @NotNull final Project project, - @NotNull final String filePath, - @NotNull final String sdkPath, - @NotNull final Task currentTask); - - void showNoSdkNotification(@NotNull final Project project); -} diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java index accecb8ad225..0978c1a4be05 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java @@ -8,9 +8,11 @@ import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -18,7 +20,6 @@ import com.intellij.openapi.vfs.VirtualFileManager; import com.jetbrains.edu.learning.StudySettings; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; -import com.jetbrains.edu.learning.checker.StudyExecutor; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.*; import com.jetbrains.edu.learning.courseFormat.tasks.ChoiceTask; @@ -624,9 +625,9 @@ public class EduAdaptiveStepicConnector { private static String getLanguageString(@NotNull Task task, @NotNull Project project) { final Language pythonLanguage = Language.findLanguageByID("Python"); if (pythonLanguage != null) { - final Sdk language = StudyExecutor.INSTANCE.forLanguage(pythonLanguage).findSdk(project); - if (language != null) { - final String versionString = language.getVersionString(); + Sdk sdk = ModuleRootManager.getInstance(ModuleManager.getInstance(project).getModules()[0]).getSdk(); + if (sdk != null) { + final String versionString = sdk.getVersionString(); if (versionString != null) { final List versionStringParts = StringUtil.split(versionString, " "); if (versionStringParts.size() == 2) { @@ -634,9 +635,6 @@ public class EduAdaptiveStepicConnector { } } } - else { - StudyUtils.showNoSdkNotification(task, project); - } } return null; } diff --git a/python/educational-python/Edu-Python/resources/META-INF/plugin.xml b/python/educational-python/Edu-Python/resources/META-INF/plugin.xml index 35419980703f..1d4b1055bfba 100644 --- a/python/educational-python/Edu-Python/resources/META-INF/plugin.xml +++ b/python/educational-python/Edu-Python/resources/META-INF/plugin.xml @@ -35,7 +35,6 @@ - diff --git a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java index 264596c26b46..f1d4c8a21eb2 100644 --- a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java +++ b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java @@ -52,7 +52,7 @@ public class PyStudyCheckAction extends StudyCheckAction { ApplicationManager.getApplication().invokeLater( () -> IdeFocusManager.getInstance(project).requestFocus(studyState.getEditor().getComponent(), true)); - final StudyTestRunner testRunner = StudyUtils.getTestRunner(task, taskDir); + final StudyTestRunner testRunner = new PyStudyTestRunner(task, taskDir); Process testProcess = null; String commandLine = ""; try { diff --git a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyExecutor.java b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyExecutor.java deleted file mode 100644 index 0bd87804ab94..000000000000 --- a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyExecutor.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2000-2014 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.jetbrains.edu.learning; - -import com.intellij.execution.RunContentExecutor; -import com.intellij.execution.configurations.GeneralCommandLine; -import com.intellij.execution.process.ProcessHandler; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.options.ShowSettingsUtil; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.ui.MessageType; -import com.intellij.openapi.ui.popup.Balloon; -import com.intellij.openapi.ui.popup.BalloonBuilder; -import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.vfs.VirtualFile; -import com.jetbrains.edu.learning.courseFormat.tasks.Task; -import com.jetbrains.edu.learning.checker.StudyExecutor; -import com.jetbrains.edu.learning.checker.StudyTestRunner; -import com.jetbrains.edu.learning.courseFormat.UserTest; -import com.jetbrains.python.run.PythonTracebackFilter; -import com.jetbrains.python.sdk.PythonSdkType; -import org.jetbrains.annotations.NotNull; - -import javax.swing.event.HyperlinkEvent; -import java.io.File; -import java.util.List; - -public class PyStudyExecutor implements StudyExecutor { - - @Override - public Sdk findSdk(@NotNull final Project project) { - return PythonSdkType.findPythonSdk(ModuleManager.getInstance(project).getModules()[0]); - } - - @Override - public StudyTestRunner getTestRunner(@NotNull final Task task, @NotNull final VirtualFile taskDir) { - return new PyStudyTestRunner(task, taskDir); - } - - @Override - public RunContentExecutor getExecutor(@NotNull final Project project, @NotNull final ProcessHandler handler) { - return new RunContentExecutor(project, handler).withFilter(new PythonTracebackFilter(project)); - } - - @Override - public void setCommandLineParameters(@NotNull final GeneralCommandLine cmd, - @NotNull final Project project, - @NotNull final String filePath, - @NotNull final String sdkPath, - @NotNull final Task currentTask) { - final List userTests = StudyTaskManager.getInstance(project).getUserTests(currentTask); - if (!userTests.isEmpty()) { - EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(currentTask.getLesson().getCourse().getLanguageById()); - if (configurator != null) { - cmd.addParameter(new File(project.getBaseDir().getPath(), "user_tester.py").getPath()); - cmd.addParameter(sdkPath); - cmd.addParameter(filePath); - } - } - else { - cmd.addParameter(filePath); - } - } - - public void showNoSdkNotification(@NotNull final Project project) { - final String text = "No Python interpreter configured for the project
Configure interpreter"; - final BalloonBuilder balloonBuilder = JBPopupFactory.getInstance(). - createHtmlTextBalloonBuilder(text, null, - MessageType.WARNING.getPopupBackground(), - event -> { - if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { - ApplicationManager.getApplication() - .invokeLater( - () -> ShowSettingsUtil.getInstance().showSettingsDialog(project, "Project Interpreter")); - } - }); - balloonBuilder.setHideOnLinkClick(true); - final Balloon balloon = balloonBuilder.createBalloon(); - StudyUtils.showCheckPopUp(project, balloon); - } -} From ce7f78de5f72b9ce451a0bf4af5039bfe43f5996 Mon Sep 17 00:00:00 2001 From: "Liana.Bakradze" Date: Fri, 7 Apr 2017 14:26:08 +0300 Subject: [PATCH 085/111] add separate class for PyCharm Task (EDU-882) --- .../CCSubtaskEditorNotificationProvider.java | 3 ++- .../jetbrains/edu/coursecreator/CCUtils.java | 3 ++- .../coursecreator/actions/CCCreateTask.java | 3 ++- .../edu/learning/StudySerializationUtils.java | 6 +++++- .../edu/learning/courseFormat/Lesson.java | 2 +- .../courseFormat/tasks/PyCharmTask.java | 21 +++++++++++++++++++ .../edu/learning/courseFormat/tasks/Task.java | 6 ++---- .../learning/stepic/EduStepicConnector.java | 3 ++- .../edu/coursecreator/CCTestCase.java | 3 ++- 9 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/PyCharmTask.java diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/CCSubtaskEditorNotificationProvider.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/CCSubtaskEditorNotificationProvider.java index 8c6c2a49b0fa..6189b8c9186f 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/CCSubtaskEditorNotificationProvider.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/CCSubtaskEditorNotificationProvider.java @@ -28,6 +28,7 @@ import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholderSubtaskInfo; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.TaskFile; +import com.jetbrains.edu.learning.courseFormat.tasks.PyCharmTask; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import com.jetbrains.edu.learning.courseFormat.tasks.TaskWithSubtasks; import org.jetbrains.annotations.NotNull; @@ -227,7 +228,7 @@ public class CCSubtaskEditorNotificationProvider extends EditorNotifications.Pro final Lesson lesson = myTask.getLesson(); final List list = lesson.getTaskList(); final int i = list.indexOf(myTask); - final Task task = new Task(); + final Task task = new PyCharmTask(); task.copyTaskParameters(myTask); for (TaskFile taskFile : task.getTaskFiles().values()) { taskFile.setTask(task); diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/CCUtils.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/CCUtils.java index 0b8815f4aa58..a8be51afe37f 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/CCUtils.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/CCUtils.java @@ -29,6 +29,7 @@ import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.StudyItem; import com.jetbrains.edu.learning.courseFormat.TaskFile; +import com.jetbrains.edu.learning.courseFormat.tasks.PyCharmTask; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import org.apache.commons.codec.binary.Base64; import org.jetbrains.annotations.NotNull; @@ -264,7 +265,7 @@ public class CCUtils { final Lesson lesson = new Lesson(); lesson.setName(EduNames.PYCHARM_ADDITIONAL); - final Task task = new Task(); + final Task task = new PyCharmTask(); task.setLesson(lesson); task.setName(EduNames.PYCHARM_ADDITIONAL); task.setIndex(1); diff --git a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java index 892f93ba0399..3f64f5dc4588 100644 --- a/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java +++ b/python/educational-core/src/com/jetbrains/edu/coursecreator/actions/CCCreateTask.java @@ -11,6 +11,7 @@ import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.StudyItem; +import com.jetbrains.edu.learning.courseFormat.tasks.PyCharmTask; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import icons.EducationalCoreIcons; import org.jetbrains.annotations.NotNull; @@ -109,7 +110,7 @@ public class CCCreateTask extends CCCreateStudyItemActionBase { @Override protected StudyItem createAndInitItem(@NotNull Course course, @Nullable StudyItem parentItem, String name, int index) { - final Task task = new Task(name); + final Task task = new PyCharmTask(name); task.setIndex(index); if (parentItem == null) { return null; diff --git a/python/educational-core/src/com/jetbrains/edu/learning/StudySerializationUtils.java b/python/educational-core/src/com/jetbrains/edu/learning/StudySerializationUtils.java index 043625347769..fb5f151f69dd 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/StudySerializationUtils.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/StudySerializationUtils.java @@ -97,6 +97,7 @@ public class StudySerializationUtils { private static String THEORY_TAG = "theoryTask"; private static String ADAPTIVE_TASK_PARAMETERS = "adaptiveTaskParameters"; private static String ADAPTIVE = "adaptive"; + public static final String PYCHARM_TASK = "PyCharmTask"; private static String TASK_WITH_SUBTASKS = "TaskWithSubtasks"; private static String THEORY_TASK = "TheoryTask"; private static String CHOICE_TASK = "ChoiceTask"; @@ -285,6 +286,9 @@ public class StudySerializationUtils { else if (Boolean.valueOf(adaptive.getAttributeValue(VALUE))) { task.setName(CODE_TASK); } + else { + task.setName(PYCHARM_TASK); + } task.removeContent(adaptiveParams); task.removeContent(theoryTask); } @@ -638,7 +642,7 @@ public class StudySerializationUtils { case "choice": return gson.fromJson(json, ChoiceTask.class); case "theory": return gson.fromJson(json, TheoryTask.class); case "code": return gson.fromJson(json, CodeTask.class); - case "pycharm": return gson.fromJson(json, Task.class); + case "pycharm": return gson.fromJson(json, PyCharmTask.class); case "subtasks": return gson.fromJson(json, TaskWithSubtasks.class); default: { LOG.warn("Unsupported task type " + taskType); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/Lesson.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/Lesson.java index 18692467e3ee..4109a93be0d9 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/Lesson.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/Lesson.java @@ -28,7 +28,7 @@ public class Lesson implements StudyItem { @Expose @SerializedName("task_list") @AbstractCollection(elementTypes = { - Task.class, + PyCharmTask.class, ChoiceTask.class, TheoryTask.class, CodeTask.class, diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/PyCharmTask.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/PyCharmTask.java new file mode 100644 index 000000000000..7ec30c7bf90f --- /dev/null +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/PyCharmTask.java @@ -0,0 +1,21 @@ +package com.jetbrains.edu.learning.courseFormat.tasks; + +import org.jetbrains.annotations.NotNull; + +/** + * Original PyCharm Edu tasks with local tests and answer placeholders + */ +public class PyCharmTask extends Task { + + public PyCharmTask() { + } + + public PyCharmTask(@NotNull String name) { + super(name); + } + + @Override + public String getTaskType() { + return "pycharm"; + } +} \ No newline at end of file diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/Task.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/Task.java index 947b2532a4d7..3b6aad423338 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/Task.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/Task.java @@ -29,7 +29,7 @@ import java.util.Map; * - go to Lesson and update elementTypes in taskList AbstractCollection. Needed for proper xml serialization * - Update TaskSerializer and TaskDeserializer in StudySerializationUtil to handle json serialization */ -public class Task implements StudyItem { +public abstract class Task implements StudyItem { @Expose private String name; // index is visible to user number of task from 1 to task number @@ -268,7 +268,5 @@ public class Task implements StudyItem { } // used in json serialization/deserialization - public String getTaskType() { - return "pycharm"; - } + public abstract String getTaskType(); } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java index a7ead47048fc..c4a1e8f777e0 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java @@ -12,6 +12,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.jetbrains.edu.learning.StudySettings; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.*; +import com.jetbrains.edu.learning.courseFormat.tasks.PyCharmTask; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import com.jetbrains.edu.learning.courseFormat.tasks.TaskWithSubtasks; import org.apache.http.HttpEntity; @@ -267,7 +268,7 @@ public class EduStepicConnector { return null; } final int lastSubtaskIndex = block.options.lastSubtaskIndex; - Task task = new Task(); + Task task = new PyCharmTask(); if (lastSubtaskIndex != 0) { task = createTaskWithSubtasks(lastSubtaskIndex); } diff --git a/python/educational-core/testSrc/com/jetbrains/edu/coursecreator/CCTestCase.java b/python/educational-core/testSrc/com/jetbrains/edu/coursecreator/CCTestCase.java index 5be02916f2fe..051964560cc6 100644 --- a/python/educational-core/testSrc/com/jetbrains/edu/coursecreator/CCTestCase.java +++ b/python/educational-core/testSrc/com/jetbrains/edu/coursecreator/CCTestCase.java @@ -19,6 +19,7 @@ import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.courseFormat.*; +import com.jetbrains.edu.learning.courseFormat.tasks.PyCharmTask; import com.jetbrains.edu.learning.courseFormat.tasks.Task; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -85,7 +86,7 @@ public abstract class CCTestCase extends CodeInsightFixtureTestCase { Lesson lesson = new Lesson(); lesson.setName("lesson1"); - Task task = new Task(); + Task task = new PyCharmTask(); task.setName("task1"); task.setIndex(1); lesson.addTask(task); From 96ab8a27a965355e678f550cae5f4612ed902573 Mon Sep 17 00:00:00 2001 From: "Liana.Bakradze" Date: Fri, 7 Apr 2017 14:35:16 +0300 Subject: [PATCH 086/111] move check listener to checker package --- python/educational-core/resources/META-INF/plugin.xml | 2 +- .../com/jetbrains/edu/learning/actions/StudyCheckAction.java | 2 +- .../edu/learning/{ => checker}/StudyCheckListener.java | 2 +- .../com/jetbrains/edu/learning/twitter/StudyTwitterAction.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename python/educational-core/src/com/jetbrains/edu/learning/{ => checker}/StudyCheckListener.java (91%) diff --git a/python/educational-core/resources/META-INF/plugin.xml b/python/educational-core/resources/META-INF/plugin.xml index aebea6fd6a7c..5f794738eaa2 100644 --- a/python/educational-core/resources/META-INF/plugin.xml +++ b/python/educational-core/resources/META-INF/plugin.xml @@ -45,7 +45,7 @@
- + diff --git a/python/educational-core/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java b/python/educational-core/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java index 984d1a5dd699..abf32c6c97e5 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/actions/StudyCheckAction.java @@ -13,7 +13,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.VirtualFile; -import com.jetbrains.edu.learning.StudyCheckListener; +import com.jetbrains.edu.learning.checker.StudyCheckListener; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.checker.StudyCheckUtils; import com.jetbrains.edu.learning.courseFormat.tasks.Task; diff --git a/python/educational-core/src/com/jetbrains/edu/learning/StudyCheckListener.java b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckListener.java similarity index 91% rename from python/educational-core/src/com/jetbrains/edu/learning/StudyCheckListener.java rename to python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckListener.java index d4896f864d27..e4f2fa636028 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/StudyCheckListener.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckListener.java @@ -1,4 +1,4 @@ -package com.jetbrains.edu.learning; +package com.jetbrains.edu.learning.checker; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.project.Project; diff --git a/python/educational-core/src/com/jetbrains/edu/learning/twitter/StudyTwitterAction.java b/python/educational-core/src/com/jetbrains/edu/learning/twitter/StudyTwitterAction.java index a1c57b92583d..360c0eba54bd 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/twitter/StudyTwitterAction.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/twitter/StudyTwitterAction.java @@ -2,7 +2,7 @@ package com.jetbrains.edu.learning.twitter; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; -import com.jetbrains.edu.learning.StudyCheckListener; +import com.jetbrains.edu.learning.checker.StudyCheckListener; import com.jetbrains.edu.learning.StudyTwitterPluginConfigurator; import com.jetbrains.edu.learning.courseFormat.StudyStatus; import com.jetbrains.edu.learning.courseFormat.tasks.Task; From 15caae587492da5de23cce96d8c6fcbf68552f9d Mon Sep 17 00:00:00 2001 From: "Liana.Bakradze" Date: Fri, 7 Apr 2017 15:24:28 +0300 Subject: [PATCH 087/111] fix Django course creation --- .../com/jetbrains/edu/learning/stepic/EduStepicConnector.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java index c4a1e8f777e0..185e53613d4c 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java @@ -302,6 +302,9 @@ public class EduStepicConnector { final List placeholders = file.getAnswerPlaceholders(); for (AnswerPlaceholder placeholder : placeholders) { final AnswerPlaceholderSubtaskInfo info = placeholder.getActiveSubtaskInfo(); + if (info == null) { + continue; + } final int offset = placeholder.getOffset(); final int length = placeholder.getLength(); if (fileText.length() > offset + length) { From c00fba9ebef73043109f503de6cb998bf3554d1e Mon Sep 17 00:00:00 2001 From: "Liana.Bakradze" Date: Fri, 7 Apr 2017 15:50:48 +0300 Subject: [PATCH 088/111] move onTaskSolved logic to StudyChecker (EDU-882) --- .../edu/learning/checker/StudyCheckTask.java | 80 ++----------------- .../edu/learning/checker/StudyCheckUtils.java | 2 +- .../learning/checker/StudyTaskChecker.java | 22 +++++ .../edu/learning/courseFormat/tasks/Task.java | 5 ++ .../courseFormat/tasks/TaskWithSubtasks.java | 64 +++++++++++++++ 5 files changed, 97 insertions(+), 76 deletions(-) create mode 100644 python/educational-core/src/com/jetbrains/edu/learning/checker/StudyTaskChecker.java diff --git a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java index 55e82678ab00..096ec8e5af8d 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java @@ -5,25 +5,22 @@ import com.intellij.execution.process.ProcessOutput; import com.intellij.ide.projectView.ProjectView; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; -import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; -import com.jetbrains.edu.learning.*; +import com.jetbrains.edu.learning.StudySettings; +import com.jetbrains.edu.learning.StudyState; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; -import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.StudyStatus; -import com.jetbrains.edu.learning.courseFormat.TaskFile; import com.jetbrains.edu.learning.courseFormat.tasks.ChoiceTask; import com.jetbrains.edu.learning.courseFormat.tasks.Task; -import com.jetbrains.edu.learning.courseFormat.tasks.TaskWithSubtasks; import com.jetbrains.edu.learning.courseFormat.tasks.TheoryTask; import com.jetbrains.edu.learning.stepic.EduAdaptiveStepicConnector; import com.jetbrains.edu.learning.stepic.EduStepicConnector; @@ -31,8 +28,6 @@ import com.jetbrains.edu.learning.stepic.StepicUser; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Map; - public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroundable { private static final Logger LOG = Logger.getInstance(StudyCheckTask.class); @@ -228,73 +223,8 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun } protected void onTaskSolved(@NotNull String message) { - final Course course = StudyTaskManager.getInstance(myProject).getCourse(); myTask.setStatus(StudyStatus.Solved); - if (course != null) { - if (course.isAdaptive()) { - ApplicationManager.getApplication().invokeLater( - () -> { - if (myTask instanceof ChoiceTask) { - StudyCheckUtils.showTestResultPopUp("Congratulations!", MessageType.INFO.getPopupBackground(), myProject); - } - else { - StudyCheckUtils.showTestResultPopUp("Congratulations!", MessageType.INFO.getPopupBackground(), myProject); - StudyCheckUtils.showTestResultsToolWindow(myProject, message, true); - } - }); - } - else { - if (myTask instanceof TaskWithSubtasks) { - boolean hasMoreSubtasks = ((TaskWithSubtasks)myTask).activeSubtaskNotLast(); - final int activeSubtaskIndex = ((TaskWithSubtasks)myTask).getActiveSubtaskIndex(); - int visibleSubtaskIndex = activeSubtaskIndex + 1; - - ApplicationManager.getApplication().invokeLater(() -> { - int subtaskSize = ((TaskWithSubtasks)myTask).getLastSubtaskIndex() + 1; - String resultMessage = !hasMoreSubtasks ? message : "Subtask " + visibleSubtaskIndex + "/" + subtaskSize + " solved"; - StudyCheckUtils.showTestResultPopUp(resultMessage, MessageType.INFO.getPopupBackground(), myProject); - if (hasMoreSubtasks) { - int nextSubtaskIndex = activeSubtaskIndex + 1; - StudySubtaskUtils.switchStep(myProject, (TaskWithSubtasks)myTask, nextSubtaskIndex); - rememberAnswers(nextSubtaskIndex); - } - }); - } - else { - ApplicationManager.getApplication().invokeLater( - () -> StudyCheckUtils.showTestResultPopUp(message, MessageType.INFO.getPopupBackground(), myProject)); - } - } - } - } - - private void rememberAnswers(int nextSubtaskIndex) { - VirtualFile taskDir = myTask.getTaskDir(myProject); - if (taskDir == null) { - return; - } - VirtualFile srcDir = taskDir.findChild(EduNames.SRC); - if (srcDir != null) { - taskDir = srcDir; - } - for (Map.Entry entry : myTask.getTaskFiles().entrySet()) { - TaskFile taskFile = entry.getValue(); - VirtualFile virtualFile = taskDir.findFileByRelativePath(entry.getKey()); - if (virtualFile == null) { - continue; - } - Document document = FileDocumentManager.getInstance().getDocument(virtualFile); - if (document == null) { - continue; - } - for (AnswerPlaceholder placeholder : taskFile.getActivePlaceholders()) { - if (placeholder.getSubtaskInfos().containsKey(nextSubtaskIndex - 1)) { - int offset = placeholder.getOffset(); - String answer = document.getText(TextRange.create(offset, offset + placeholder.getRealLength())); - placeholder.getSubtaskInfos().get(nextSubtaskIndex - 1).setAnswer(answer); - } - } - } + myTask.getChecker(myProject).onTaskSolved(message); } private void runAfterTaskCheckedActions() { diff --git a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java index 7ba9aef911f5..a6da62dffb4e 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java @@ -108,7 +108,7 @@ public class StudyCheckUtils { } - public static void showTestResultPopUp(final String text, Color color, @NotNull final Project project) { + public static void showTestResultPopUp(@NotNull final String text, Color color, @NotNull final Project project) { BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(text, null, color, null); final Balloon balloon = balloonBuilder.createBalloon(); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyTaskChecker.java b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyTaskChecker.java new file mode 100644 index 000000000000..704cfc0b960f --- /dev/null +++ b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyTaskChecker.java @@ -0,0 +1,22 @@ +package com.jetbrains.edu.learning.checker; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; +import com.jetbrains.edu.learning.courseFormat.tasks.Task; +import org.jetbrains.annotations.NotNull; + +public class StudyTaskChecker { + @NotNull protected final T myTask; + @NotNull protected final Project myProject; + + public StudyTaskChecker(@NotNull T task, @NotNull Project project) { + myTask = task; + myProject = project; + } + + public void onTaskSolved(@NotNull String message) { + ApplicationManager.getApplication().invokeLater( + () -> StudyCheckUtils.showTestResultPopUp(message, MessageType.INFO.getPopupBackground(), myProject)); + } +} diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/Task.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/Task.java index 3b6aad423338..4bfc083c656e 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/Task.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/Task.java @@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.xmlb.XmlSerializer; import com.intellij.util.xmlb.annotations.Transient; +import com.jetbrains.edu.learning.checker.StudyTaskChecker; import com.jetbrains.edu.learning.EduPluginConfigurator; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.*; @@ -269,4 +270,8 @@ public abstract class Task implements StudyItem { // used in json serialization/deserialization public abstract String getTaskType(); + + public StudyTaskChecker getChecker(@NotNull Project project) { + return new StudyTaskChecker<>(this, project); + } } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/TaskWithSubtasks.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/TaskWithSubtasks.java index ac10657b829c..63d70d5fd3f4 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/TaskWithSubtasks.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/TaskWithSubtasks.java @@ -2,11 +2,24 @@ package com.jetbrains.edu.learning.courseFormat.tasks; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.edu.learning.StudySubtaskUtils; +import com.jetbrains.edu.learning.checker.StudyCheckUtils; +import com.jetbrains.edu.learning.checker.StudyTaskChecker; +import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.StudyStatus; import com.jetbrains.edu.learning.courseFormat.TaskFile; import org.jetbrains.annotations.NotNull; +import java.util.Map; + public class TaskWithSubtasks extends Task { private int myActiveSubtaskIndex = 0; @SerializedName("last_subtask_index") @@ -58,4 +71,55 @@ public class TaskWithSubtasks extends Task { public String getTaskType() { return "subtasks"; } + + @Override + public StudyTaskChecker getChecker(@NotNull Project project) { + return new StudyTaskChecker(this, project) { + @Override + public void onTaskSolved(@NotNull String message) { + boolean hasMoreSubtasks = myTask.activeSubtaskNotLast(); + final int activeSubtaskIndex = myTask.getActiveSubtaskIndex(); + int visibleSubtaskIndex = activeSubtaskIndex + 1; + ApplicationManager.getApplication().invokeLater(() -> { + int subtaskSize = myTask.getLastSubtaskIndex() + 1; + String resultMessage = !hasMoreSubtasks ? message : "Subtask " + visibleSubtaskIndex + "/" + subtaskSize + " solved"; + StudyCheckUtils.showTestResultPopUp(resultMessage, MessageType.INFO.getPopupBackground(), myProject); + if (hasMoreSubtasks) { + int nextSubtaskIndex = activeSubtaskIndex + 1; + StudySubtaskUtils.switchStep(myProject, myTask, nextSubtaskIndex); + rememberAnswers(nextSubtaskIndex, myTask); + } + }); + } + + private void rememberAnswers(int nextSubtaskIndex, @NotNull TaskWithSubtasks task) { + VirtualFile taskDir = task.getTaskDir(myProject); + if (taskDir == null) { + return; + } + VirtualFile srcDir = taskDir.findChild(EduNames.SRC); + if (srcDir != null) { + taskDir = srcDir; + } + for (Map.Entry entry : task.getTaskFiles().entrySet()) { + TaskFile taskFile = entry.getValue(); + VirtualFile virtualFile = taskDir.findFileByRelativePath(entry.getKey()); + if (virtualFile == null) { + continue; + } + Document document = FileDocumentManager.getInstance().getDocument(virtualFile); + if (document == null) { + continue; + } + for (AnswerPlaceholder placeholder : taskFile.getActivePlaceholders()) { + if (placeholder.getSubtaskInfos().containsKey(nextSubtaskIndex - 1)) { + int offset = placeholder.getOffset(); + String answer = document.getText(TextRange.create(offset, offset + placeholder.getRealLength())); + placeholder.getSubtaskInfos().get(nextSubtaskIndex - 1).setAnswer(answer); + } + } + } + } + }; + } } From 230e7528c4ca23b1d1b515eed3cbd3a9d6c713c3 Mon Sep 17 00:00:00 2001 From: "Liana.Bakradze" Date: Fri, 7 Apr 2017 16:11:47 +0300 Subject: [PATCH 089/111] move onTaskFailed logic to StudyChecker (EDU-882) --- .../edu/learning/checker/StudyCheckTask.java | 15 +----- .../edu/learning/checker/StudyCheckUtils.java | 50 ++++++++++--------- .../learning/checker/StudyTaskChecker.java | 5 ++ .../courseFormat/tasks/ChoiceTask.java | 23 +++++++++ .../learning/courseFormat/tasks/CodeTask.java | 14 ++++++ .../edu/learning/PyStudyCheckAction.java | 35 +------------ 6 files changed, 71 insertions(+), 71 deletions(-) diff --git a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java index 096ec8e5af8d..09e411d82931 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckTask.java @@ -205,21 +205,8 @@ public class StudyCheckTask extends com.intellij.openapi.progress.Task.Backgroun } protected void onTaskFailed(@NotNull String message) { - final Course course = StudyTaskManager.getInstance(myProject).getCourse(); myTask.setStatus(StudyStatus.Failed); - if (course != null) { - if (course.isAdaptive()) { - ApplicationManager.getApplication().invokeLater( - () -> { - StudyCheckUtils.showTestResultPopUp("Failed", MessageType.ERROR.getPopupBackground(), myProject); - StudyCheckUtils.showTestResultsToolWindow(myProject, message, false); - }); - } - else { - ApplicationManager.getApplication() - .invokeLater(() -> StudyCheckUtils.showTestResultPopUp(message, MessageType.ERROR.getPopupBackground(), myProject)); - } - } + myTask.getChecker(myProject).onTaskFailed(message); } protected void onTaskSolved(@NotNull String message) { diff --git a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java index a6da62dffb4e..761cb2cfab6d 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java @@ -28,8 +28,8 @@ import com.jetbrains.edu.learning.core.EduDocumentListener; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.core.EduUtils; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; -import com.jetbrains.edu.learning.courseFormat.tasks.Task; import com.jetbrains.edu.learning.courseFormat.TaskFile; +import com.jetbrains.edu.learning.courseFormat.tasks.Task; import com.jetbrains.edu.learning.editor.StudyEditor; import com.jetbrains.edu.learning.navigation.StudyNavigator; import com.jetbrains.edu.learning.ui.StudyTestResultsToolWindowFactory; @@ -202,29 +202,31 @@ public class StudyCheckUtils { } public static void showTestResultsToolWindow(@NotNull final Project project, @NotNull final String message, boolean solved) { - final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project); - ToolWindow window = toolWindowManager.getToolWindow(StudyTestResultsToolWindowFactoryKt.ID); - if (window == null) { - toolWindowManager.registerToolWindow(StudyTestResultsToolWindowFactoryKt.ID, true, ToolWindowAnchor.BOTTOM); - window = toolWindowManager.getToolWindow(StudyTestResultsToolWindowFactoryKt.ID); - new StudyTestResultsToolWindowFactory().createToolWindowContent(project, window); - } - - final Content[] contents = window.getContentManager().getContents(); - for (Content content : contents) { - final JComponent component = content.getComponent(); - if (component instanceof ConsoleViewImpl) { - ((ConsoleViewImpl)component).clear(); - if (!solved) { - ((ConsoleViewImpl)component).print(message, ConsoleViewContentType.ERROR_OUTPUT); - } - else { - ((ConsoleViewImpl)component).print(message, ConsoleViewContentType.NORMAL_OUTPUT); - } - window.setAvailable(true, () -> {}); - window.show(() -> {}); - return; + ApplicationManager.getApplication().invokeLater(() -> { + final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project); + ToolWindow window = toolWindowManager.getToolWindow(StudyTestResultsToolWindowFactoryKt.ID); + if (window == null) { + toolWindowManager.registerToolWindow(StudyTestResultsToolWindowFactoryKt.ID, true, ToolWindowAnchor.BOTTOM); + window = toolWindowManager.getToolWindow(StudyTestResultsToolWindowFactoryKt.ID); + new StudyTestResultsToolWindowFactory().createToolWindowContent(project, window); } - } + + final Content[] contents = window.getContentManager().getContents(); + for (Content content : contents) { + final JComponent component = content.getComponent(); + if (component instanceof ConsoleViewImpl) { + ((ConsoleViewImpl)component).clear(); + if (!solved) { + ((ConsoleViewImpl)component).print(message, ConsoleViewContentType.ERROR_OUTPUT); + } + else { + ((ConsoleViewImpl)component).print(message, ConsoleViewContentType.NORMAL_OUTPUT); + } + window.setAvailable(true, () -> {}); + window.show(() -> {}); + return; + } + } + }); } } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyTaskChecker.java b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyTaskChecker.java index 704cfc0b960f..879621a1a725 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyTaskChecker.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyTaskChecker.java @@ -19,4 +19,9 @@ public class StudyTaskChecker { ApplicationManager.getApplication().invokeLater( () -> StudyCheckUtils.showTestResultPopUp(message, MessageType.INFO.getPopupBackground(), myProject)); } + + public void onTaskFailed(@NotNull String message) { + ApplicationManager.getApplication() + .invokeLater(() -> StudyCheckUtils.showTestResultPopUp(message, MessageType.ERROR.getPopupBackground(), myProject)); + } } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/ChoiceTask.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/ChoiceTask.java index f7ce2ae9a162..476af7826116 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/ChoiceTask.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/ChoiceTask.java @@ -2,6 +2,11 @@ package com.jetbrains.edu.learning.courseFormat.tasks; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; +import com.intellij.openapi.project.Project; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.checker.StudyTaskChecker; +import com.jetbrains.edu.learning.editor.StudyChoiceVariantsPanel; +import com.jetbrains.edu.learning.ui.StudyToolWindow; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -48,4 +53,22 @@ public class ChoiceTask extends Task { public String getTaskType() { return "choice"; } + + @Override + public StudyTaskChecker getChecker(@NotNull Project project) { + return new StudyTaskChecker(this, project) { + @Override + public void onTaskFailed(@NotNull String message) { + super.onTaskFailed(message); + repaintChoicePanel(project, myTask); + } + + private void repaintChoicePanel(@NotNull Project project, @NotNull ChoiceTask task) { + final StudyToolWindow toolWindow = StudyUtils.getStudyToolWindow(project); + if (toolWindow != null) { + toolWindow.setBottomComponent(new StudyChoiceVariantsPanel(task)); + } + } + }; + } } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/CodeTask.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/CodeTask.java index fb2d701cb6ac..3493f17ac262 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/CodeTask.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/CodeTask.java @@ -1,5 +1,8 @@ package com.jetbrains.edu.learning.courseFormat.tasks; +import com.intellij.openapi.project.Project; +import com.jetbrains.edu.learning.checker.StudyCheckUtils; +import com.jetbrains.edu.learning.checker.StudyTaskChecker; import org.jetbrains.annotations.NotNull; public class CodeTask extends Task { @@ -14,4 +17,15 @@ public class CodeTask extends Task { public String getTaskType() { return "code"; } + + @Override + public StudyTaskChecker getChecker(@NotNull Project project) { + return new StudyTaskChecker(this, project) { + @Override + public void onTaskFailed(@NotNull String message) { + super.onTaskFailed("Wrong solution"); + StudyCheckUtils.showTestResultsToolWindow(myProject, message, false); + } + }; + } } diff --git a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java index f1d4c8a21eb2..1948c1ce49a8 100644 --- a/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java +++ b/python/educational-python/Edu-Python/src/com/jetbrains/edu/learning/PyStudyCheckAction.java @@ -6,7 +6,6 @@ import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.IdeFocusManager; import com.jetbrains.edu.learning.actions.StudyCheckAction; @@ -15,14 +14,10 @@ import com.jetbrains.edu.learning.checker.StudyCheckUtils; import com.jetbrains.edu.learning.checker.StudyTestRunner; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; -import com.jetbrains.edu.learning.courseFormat.StudyStatus; import com.jetbrains.edu.learning.courseFormat.TaskFile; -import com.jetbrains.edu.learning.courseFormat.tasks.ChoiceTask; import com.jetbrains.edu.learning.courseFormat.tasks.Task; -import com.jetbrains.edu.learning.editor.StudyChoiceVariantsPanel; import com.jetbrains.edu.learning.editor.StudyEditor; import com.jetbrains.edu.learning.statistics.EduUsagesCollector; -import com.jetbrains.edu.learning.ui.StudyToolWindow; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -83,9 +78,9 @@ public class PyStudyCheckAction extends StudyCheckAction { return new StudyCheckTask(project, studyState, myCheckInProgress, testProcess, commandLine) { @Override protected void onTaskFailed(@NotNull String message) { + super.onTaskFailed(message); ApplicationManager.getApplication().invokeLater(() -> { if (myTaskDir == null) return; - myTask.setStatus(StudyStatus.Failed); for (Map.Entry entry : myTask.getTaskFiles().entrySet()) { final String name = entry.getKey(); final TaskFile taskFile = entry.getValue(); @@ -99,38 +94,12 @@ public class PyStudyCheckAction extends StudyCheckAction { () -> StudyCheckUtils.runSmartTestProcess(myTaskDir, testRunner, name, taskFile, project))); } } - final StudyToolWindow toolWindow = StudyUtils.getStudyToolWindow(project); - if (toolWindow != null) { - final Course course = StudyTaskManager.getInstance(project).getCourse(); - if (course != null) { - if (course.isAdaptive()) { - if (myTask instanceof ChoiceTask) { - StudyCheckUtils.showTestResultPopUp("Wrong answer", MessageType.ERROR.getPopupBackground(), project); - repaintChoicePanel(project, (ChoiceTask)myTask); - } - else { - StudyCheckUtils.showTestResultPopUp("Wrong answer", MessageType.ERROR.getPopupBackground(), project); - StudyCheckUtils.showTestResultsToolWindow(project, message, false); - } - } - else { - StudyCheckUtils.showTestResultPopUp(message, MessageType.ERROR.getPopupBackground(), project); - } - } - StudyCheckUtils.navigateToFailedPlaceholder(myStudyState, myTask, myTaskDir, project); - } + StudyCheckUtils.navigateToFailedPlaceholder(myStudyState, myTask, myTaskDir, project); }); } }; } - private static void repaintChoicePanel(@NotNull Project project, @NotNull ChoiceTask task) { - final StudyToolWindow toolWindow = StudyUtils.getStudyToolWindow(project); - if (toolWindow != null) { - toolWindow.setBottomComponent(new StudyChoiceVariantsPanel(task)); - } - } - @Nullable private static VirtualFile getTaskVirtualFile(@NotNull final StudyState studyState, @NotNull final Task task, From c14f39837498b973396ee077e28953c84e0d4dd6 Mon Sep 17 00:00:00 2001 From: "Liana.Bakradze" Date: Fri, 7 Apr 2017 16:43:45 +0300 Subject: [PATCH 090/111] remove redundant parameter (EDU-882) --- .../edu/learning/checker/StudyCheckUtils.java | 14 ++++---------- .../edu/learning/courseFormat/tasks/CodeTask.java | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java index 761cb2cfab6d..714433bcb03b 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/checker/StudyCheckUtils.java @@ -201,7 +201,7 @@ public class StudyCheckUtils { } } - public static void showTestResultsToolWindow(@NotNull final Project project, @NotNull final String message, boolean solved) { + public static void showTestResultsToolWindow(@NotNull final Project project, @NotNull final String message) { ApplicationManager.getApplication().invokeLater(() -> { final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project); ToolWindow window = toolWindowManager.getToolWindow(StudyTestResultsToolWindowFactoryKt.ID); @@ -216,15 +216,9 @@ public class StudyCheckUtils { final JComponent component = content.getComponent(); if (component instanceof ConsoleViewImpl) { ((ConsoleViewImpl)component).clear(); - if (!solved) { - ((ConsoleViewImpl)component).print(message, ConsoleViewContentType.ERROR_OUTPUT); - } - else { - ((ConsoleViewImpl)component).print(message, ConsoleViewContentType.NORMAL_OUTPUT); - } - window.setAvailable(true, () -> {}); - window.show(() -> {}); - return; + ((ConsoleViewImpl)component).print(message, ConsoleViewContentType.ERROR_OUTPUT); + window.setAvailable(true,null); + window.show(null); } } }); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/CodeTask.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/CodeTask.java index 3493f17ac262..b82c478c43d9 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/CodeTask.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/CodeTask.java @@ -24,7 +24,7 @@ public class CodeTask extends Task { @Override public void onTaskFailed(@NotNull String message) { super.onTaskFailed("Wrong solution"); - StudyCheckUtils.showTestResultsToolWindow(myProject, message, false); + StudyCheckUtils.showTestResultsToolWindow(myProject, message); } }; } From da2760736028b73673aad21cdeb5568d3dc76c40 Mon Sep 17 00:00:00 2001 From: "Liana.Bakradze" Date: Fri, 7 Apr 2017 16:51:39 +0300 Subject: [PATCH 091/111] remove unused parameter --- .../edu/learning/stepic/EduAdaptiveStepicConnector.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java index 0978c1a4be05..f94ecb071d2e 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java @@ -455,7 +455,7 @@ public class EduAdaptiveStepicConnector { } } else { - final String templateForTask = getCodeTemplateForTask(project, task, step.options.codeTemplates); + final String templateForTask = getCodeTemplateForTask(project, step.options.codeTemplates); String text = templateForTask == null ? "# write your answer here \n" : templateForTask; createMockTaskFile(task, text); } @@ -463,10 +463,9 @@ public class EduAdaptiveStepicConnector { } private static String getCodeTemplateForTask(@NotNull Project project, - @NotNull Task task, @Nullable StepicWrappers.CodeTemplatesWrapper codeTemplates) { if (codeTemplates != null) { - final String languageString = getLanguageString(task, project); + final String languageString = getLanguageString(project); if (languageString != null) { return codeTemplates.getTemplateForLanguage(languageString); } @@ -622,7 +621,7 @@ public class EduAdaptiveStepicConnector { } @Nullable - private static String getLanguageString(@NotNull Task task, @NotNull Project project) { + private static String getLanguageString(@NotNull Project project) { final Language pythonLanguage = Language.findLanguageByID("Python"); if (pythonLanguage != null) { Sdk sdk = ModuleRootManager.getInstance(ModuleManager.getInstance(project).getModules()[0]).getSdk(); From fd54035b21120454863e2d36b67b949be54057e3 Mon Sep 17 00:00:00 2001 From: "Liana.Bakradze" Date: Fri, 7 Apr 2017 19:22:42 +0300 Subject: [PATCH 092/111] extract TaskWithSubtasksChecker (EDU-882) --- .../checker/TaskWithSubtasksChecker.java | 70 +++++++++++++++++++ .../courseFormat/tasks/TaskWithSubtasks.java | 60 +--------------- 2 files changed, 72 insertions(+), 58 deletions(-) create mode 100644 python/educational-core/src/com/jetbrains/edu/learning/checker/TaskWithSubtasksChecker.java diff --git a/python/educational-core/src/com/jetbrains/edu/learning/checker/TaskWithSubtasksChecker.java b/python/educational-core/src/com/jetbrains/edu/learning/checker/TaskWithSubtasksChecker.java new file mode 100644 index 000000000000..f18b15fe2eff --- /dev/null +++ b/python/educational-core/src/com/jetbrains/edu/learning/checker/TaskWithSubtasksChecker.java @@ -0,0 +1,70 @@ +package com.jetbrains.edu.learning.checker; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.edu.learning.StudySubtaskUtils; +import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; +import com.jetbrains.edu.learning.courseFormat.TaskFile; +import com.jetbrains.edu.learning.courseFormat.tasks.TaskWithSubtasks; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public class TaskWithSubtasksChecker extends StudyTaskChecker { + public TaskWithSubtasksChecker(@NotNull TaskWithSubtasks task, + @NotNull Project project) { + super(task, project); + } + + @Override + public void onTaskSolved(@NotNull String message) { + boolean hasMoreSubtasks = myTask.activeSubtaskNotLast(); + final int activeSubtaskIndex = myTask.getActiveSubtaskIndex(); + int visibleSubtaskIndex = activeSubtaskIndex + 1; + ApplicationManager.getApplication().invokeLater(() -> { + int subtaskSize = myTask.getLastSubtaskIndex() + 1; + String resultMessage = !hasMoreSubtasks ? message : "Subtask " + visibleSubtaskIndex + "/" + subtaskSize + " solved"; + StudyCheckUtils.showTestResultPopUp(resultMessage, MessageType.INFO.getPopupBackground(), myProject); + if (hasMoreSubtasks) { + int nextSubtaskIndex = activeSubtaskIndex + 1; + StudySubtaskUtils.switchStep(myProject, myTask, nextSubtaskIndex); + rememberAnswers(nextSubtaskIndex, myTask); + } + }); + } + + private void rememberAnswers(int nextSubtaskIndex, @NotNull TaskWithSubtasks task) { + VirtualFile taskDir = task.getTaskDir(myProject); + if (taskDir == null) { + return; + } + VirtualFile srcDir = taskDir.findChild(EduNames.SRC); + if (srcDir != null) { + taskDir = srcDir; + } + for (Map.Entry entry : task.getTaskFiles().entrySet()) { + TaskFile taskFile = entry.getValue(); + VirtualFile virtualFile = taskDir.findFileByRelativePath(entry.getKey()); + if (virtualFile == null) { + continue; + } + Document document = FileDocumentManager.getInstance().getDocument(virtualFile); + if (document == null) { + continue; + } + for (AnswerPlaceholder placeholder : taskFile.getActivePlaceholders()) { + if (placeholder.getSubtaskInfos().containsKey(nextSubtaskIndex - 1)) { + int offset = placeholder.getOffset(); + String answer = document.getText(TextRange.create(offset, offset + placeholder.getRealLength())); + placeholder.getSubtaskInfos().get(nextSubtaskIndex - 1).setAnswer(answer); + } + } + } + } +} diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/TaskWithSubtasks.java b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/TaskWithSubtasks.java index 63d70d5fd3f4..6146fb3e9df7 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/TaskWithSubtasks.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseFormat/tasks/TaskWithSubtasks.java @@ -2,24 +2,14 @@ package com.jetbrains.edu.learning.courseFormat.tasks; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.MessageType; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.vfs.VirtualFile; -import com.jetbrains.edu.learning.StudySubtaskUtils; -import com.jetbrains.edu.learning.checker.StudyCheckUtils; import com.jetbrains.edu.learning.checker.StudyTaskChecker; -import com.jetbrains.edu.learning.core.EduNames; +import com.jetbrains.edu.learning.checker.TaskWithSubtasksChecker; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; import com.jetbrains.edu.learning.courseFormat.StudyStatus; import com.jetbrains.edu.learning.courseFormat.TaskFile; import org.jetbrains.annotations.NotNull; -import java.util.Map; - public class TaskWithSubtasks extends Task { private int myActiveSubtaskIndex = 0; @SerializedName("last_subtask_index") @@ -74,52 +64,6 @@ public class TaskWithSubtasks extends Task { @Override public StudyTaskChecker getChecker(@NotNull Project project) { - return new StudyTaskChecker(this, project) { - @Override - public void onTaskSolved(@NotNull String message) { - boolean hasMoreSubtasks = myTask.activeSubtaskNotLast(); - final int activeSubtaskIndex = myTask.getActiveSubtaskIndex(); - int visibleSubtaskIndex = activeSubtaskIndex + 1; - ApplicationManager.getApplication().invokeLater(() -> { - int subtaskSize = myTask.getLastSubtaskIndex() + 1; - String resultMessage = !hasMoreSubtasks ? message : "Subtask " + visibleSubtaskIndex + "/" + subtaskSize + " solved"; - StudyCheckUtils.showTestResultPopUp(resultMessage, MessageType.INFO.getPopupBackground(), myProject); - if (hasMoreSubtasks) { - int nextSubtaskIndex = activeSubtaskIndex + 1; - StudySubtaskUtils.switchStep(myProject, myTask, nextSubtaskIndex); - rememberAnswers(nextSubtaskIndex, myTask); - } - }); - } - - private void rememberAnswers(int nextSubtaskIndex, @NotNull TaskWithSubtasks task) { - VirtualFile taskDir = task.getTaskDir(myProject); - if (taskDir == null) { - return; - } - VirtualFile srcDir = taskDir.findChild(EduNames.SRC); - if (srcDir != null) { - taskDir = srcDir; - } - for (Map.Entry entry : task.getTaskFiles().entrySet()) { - TaskFile taskFile = entry.getValue(); - VirtualFile virtualFile = taskDir.findFileByRelativePath(entry.getKey()); - if (virtualFile == null) { - continue; - } - Document document = FileDocumentManager.getInstance().getDocument(virtualFile); - if (document == null) { - continue; - } - for (AnswerPlaceholder placeholder : taskFile.getActivePlaceholders()) { - if (placeholder.getSubtaskInfos().containsKey(nextSubtaskIndex - 1)) { - int offset = placeholder.getOffset(); - String answer = document.getText(TextRange.create(offset, offset + placeholder.getRealLength())); - placeholder.getSubtaskInfos().get(nextSubtaskIndex - 1).setAnswer(answer); - } - } - } - } - }; + return new TaskWithSubtasksChecker(this, project); } } From 2a47148d94f7e26696a376b21bb8e0dcc1e15da3 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 7 Apr 2017 18:48:45 +0200 Subject: [PATCH 093/111] [tests] message texts in Javadoc highlighting tests --- .../daemonCodeAnalyzer/javaDoc/BadCharacters.java | 8 ++++---- .../daemonCodeAnalyzer/javaDoc/BadReference.java | 8 ++++---- .../daemonCodeAnalyzer/javaDoc/Exception0.java | 12 ++++++------ .../daemonCodeAnalyzer/javaDoc/InheritJavaDoc.java | 7 +++---- .../daemonCodeAnalyzer/javaDoc/JavadocPeriod.java | 6 ++---- .../daemonCodeAnalyzer/javaDoc/JavadocPeriod2.java | 12 +++++------- .../daemonCodeAnalyzer/javaDoc/Link0.java | 14 ++++++++------ .../javaDoc/MissingReturnDescription.java | 6 +++--- .../daemonCodeAnalyzer/javaDoc/MultipleThrows.java | 7 ++++--- .../daemonCodeAnalyzer/javaDoc/Param0.java | 5 ++--- .../daemonCodeAnalyzer/javaDoc/Param2.java | 9 ++++----- .../daemonCodeAnalyzer/javaDoc/Param4.java | 13 ++++++------- .../daemonCodeAnalyzer/javaDoc/Return0.java | 8 ++++---- .../daemonCodeAnalyzer/javaDoc/See0.java | 12 +++++++----- .../daemonCodeAnalyzer/javaDoc/SeeConstants.java | 9 ++++----- .../javaDoc/UnknownInlineTag.java | 8 ++++---- .../daemonCodeAnalyzer/javaDoc/UnknownTags.java | 8 ++++---- .../javaDoc/ValueBadReference.java | 10 +++++----- .../javaDoc/ValueNotOnField.java | 10 +++++----- .../javaDoc/ValueNotOnStaticField.java | 10 +++++----- .../javaDoc/ValueOnNotInitializedField.java | 10 +++++----- .../javaDoc/ValueReference14.java | 12 ++++++------ 22 files changed, 100 insertions(+), 104 deletions(-) diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/BadCharacters.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/BadCharacters.java index 1bfd88961182..050443d3b604 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/BadCharacters.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/BadCharacters.java @@ -1,10 +1,10 @@ import java.util.*; -class Test { - public void read(List list){} +class Test { + public void read(List list) {} /** - * @see #read(java.util.List<T>) + * @see #read(java.util.List<T>) */ - public void write(){} + public void write() {} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/BadReference.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/BadReference.java index 36c2c8581051..ff20c956461b 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/BadReference.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/BadReference.java @@ -1,8 +1,8 @@ class Test { - /** - * This element was written by {@link Test#write(Object, XmlWriter)} + /** + * This element was written by {@link Test#write(Object, XmlWriter)} * method. So read and write methods should be consistent. */ - public void read(){} - public void write(Object o, XmlWriter writer){} + public void read() {} + public void write(Object o, XmlWriter writer) {} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Exception0.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Exception0.java index 66281ea58bb7..5e9f1c94b34d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Exception0.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Exception0.java @@ -1,8 +1,8 @@ class Test { - /** - * @throws SomeClass asdfasd - */ - public void foo() {} - - class SomeClass {} + /** + * @throws SomeClass asdfasd + */ + public void foo() {} + + class SomeClass {} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/InheritJavaDoc.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/InheritJavaDoc.java index 75abbd9cb85b..01a2dfe60e2a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/InheritJavaDoc.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/InheritJavaDoc.java @@ -1,7 +1,6 @@ class Test { /** - * @inheritDoc - */ - void a() { - } + * @inheritDoc + */ + void a() {} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/JavadocPeriod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/JavadocPeriod.java index f7ef1c13ea0b..cd7ffafc1d72 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/JavadocPeriod.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/JavadocPeriod.java @@ -1,6 +1,4 @@ -/** +/** * Missing dot */ -class Test { - -} \ No newline at end of file +class Test { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/JavadocPeriod2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/JavadocPeriod2.java index 58f70109bfa0..4d6d004acebf 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/JavadocPeriod2.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/JavadocPeriod2.java @@ -1,7 +1,5 @@ -/** -* Do smth -* @author me. -*/ -class Test { - -} \ No newline at end of file +/** + * Do smth + * @author me. + */ +class Test { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Link0.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Link0.java index 733cec2da1a9..c09a5b45e78e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Link0.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Link0.java @@ -1,8 +1,10 @@ class Test { - /** - * @param ppp see {@link #Test} - */ - public void i(int ppp) {} - - class A{ public void foo() {}} + /** + * @param ppp see {@link #Test} + */ + public void i(int ppp) {} + + class A { + public void foo() {} + } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/MissingReturnDescription.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/MissingReturnDescription.java index f542e0d79de8..bf16275f84ea 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/MissingReturnDescription.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/MissingReturnDescription.java @@ -1,8 +1,8 @@ class MissingRetunDescription { /** - * @return - * @throws Exception in some case - */ + * @return + * @throws Exception in some case + */ public boolean foo() throws Exception { return false; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/MultipleThrows.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/MultipleThrows.java index 6fc69105c3e9..bac7e90b04ac 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/MultipleThrows.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/MultipleThrows.java @@ -1,9 +1,10 @@ import java.io.IOException; + class Test { /** - * @throws IOException in some case - * @throws IOException - */ + * @throws IOException in some case + * @throws IOException + */ void a() throws IOException{ throw new IOException(); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Param0.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Param0.java index 485ae4576695..7ac2339bdef9 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Param0.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Param0.java @@ -1,5 +1,4 @@ /** - * @param myParam paramDescription + * @param myParam paramDescription */ -class Test { -} \ No newline at end of file +class Test { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Param2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Param2.java index b81780d00505..b28d9e471b32 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Param2.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Param2.java @@ -1,7 +1,6 @@ class Test { - /** - * @param param some param - */ - public void foo() { - } + /** + * @param param some param + */ + public void foo() { } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Param4.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Param4.java index 0e2294a1c9d2..c1daf70f6ef3 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Param4.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Param4.java @@ -1,8 +1,7 @@ class Test { - - /** - * @param i here description goes - * @return - */ - int d(){return 1;} -} + /** + * @param i here description goes + * @return + */ + int d() { return 1; } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Return0.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Return0.java index 08614e1eae6e..75b9c22faeba 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Return0.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Return0.java @@ -1,6 +1,6 @@ class Test { - /** - * @return returns - */ - public void foo() {} + /** + * @return returns + */ + public void foo() {} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See0.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See0.java index 3b16ac9fd196..b77e3f7ceb60 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See0.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/See0.java @@ -1,8 +1,10 @@ class Test { - /** - * @see A#someField - */ - public void i() {} + /** + * @see A#someField + */ + public void i() {} - class A{ public void foo() {}} + class A { + public void foo() {} + } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/SeeConstants.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/SeeConstants.java index 1437f1c27e9e..b234250d6e27 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/SeeConstants.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/SeeConstants.java @@ -1,12 +1,11 @@ public class SeeConstants { public static final String III = ""; - public static final String UUU=""; + public static final String UUU = ""; /** - * @see SeeConstants.III + * @see SeeConstants.III * @see SeeConstants#UUU * @param args blah-blah */ - public static void main(String[] args) { - } -} + public static void main(String[] args) { } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/UnknownInlineTag.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/UnknownInlineTag.java index 75a457b97312..df727c30c76c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/UnknownInlineTag.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/UnknownInlineTag.java @@ -1,19 +1,19 @@ /** - * {@linked} + * {@linked} */ class Foo { /** - * @param i some param {@vaaalue #field} + * @param i some param {@vaaalue #field} */ void foo(int i) {} /** - * {@linke} + * {@linke} */ int field; /** - * Don't ever think of going here: {@link/login} + * Don't ever think of going here: {@link/login} */ void m() {} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/UnknownTags.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/UnknownTags.java index 4c91f3c2d5ec..29dff08ee67d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/UnknownTags.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/UnknownTags.java @@ -1,14 +1,14 @@ /** - * @foo + * @foo */ class Foo { /** - * @foo + * @foo */ void foo() {} /** - * @foo - */ + * @foo + */ int field; } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueBadReference.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueBadReference.java index 1a5b18185041..abb4b66f1da2 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueBadReference.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueBadReference.java @@ -1,7 +1,7 @@ class Test { - /** - * Value is {@value #badReference} - * @param ppp . - */ - public void i(int ppp) {} + /** + * Value is {@value #badReference} + * @param ppp . + */ + public void i(int ppp) {} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueNotOnField.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueNotOnField.java index 69cc30527921..2e70d9636133 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueNotOnField.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueNotOnField.java @@ -1,8 +1,8 @@ class Test { - /** - * Value is {@value #g} - */ - public void i() {} + /** + * Value is {@value #g} + */ + public void i() {} - public void g() {} + public void g() {} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueNotOnStaticField.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueNotOnStaticField.java index 9489b82d22d4..712b88cdd0a6 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueNotOnStaticField.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueNotOnStaticField.java @@ -1,8 +1,8 @@ class Test { - public int A = 1; + public int A = 1; - /** - * Value is {@value #A} - */ - public void i() {} + /** + * Value is {@value #A} + */ + public void i() {} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueOnNotInitializedField.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueOnNotInitializedField.java index a386784bcb6f..fdf397bcbe07 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueOnNotInitializedField.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueOnNotInitializedField.java @@ -1,8 +1,8 @@ class Test { - public static int A; + public static int A; - /** - * Value is {@value #A} - */ - public void i() {} + /** + * Value is {@value #A} + */ + public void i() {} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueReference14.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueReference14.java index 3534826a72f0..73ea9106a801 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueReference14.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/ValueReference14.java @@ -1,9 +1,9 @@ class Test { - public static final int A = 1; + public static final int A = 1; - /** - * Value is {@value #A} - * @param ppp . - */ - public void i(int ppp) {} + /** + * Value is {@value #A} + * @param ppp . + */ + public void i(int ppp) {} } \ No newline at end of file From 428b8c6ed7323bf389831d8c976b1b0a480f3738 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 7 Apr 2017 18:50:36 +0200 Subject: [PATCH 094/111] Cleanup (duplication) --- .../daemon/JavadocHighlightingTest.java | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java index 1eb10eae5df9..f563d896978f 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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,7 +19,6 @@ import com.intellij.JavaTestUtil; import com.intellij.codeInspection.javaDoc.JavaDocLocalInspection; import com.intellij.codeInspection.javaDoc.JavaDocReferenceInspection; import com.intellij.openapi.paths.WebReference; -import com.intellij.openapi.roots.LanguageLevelProjectExtension; import com.intellij.openapi.vcs.IssueNavigationConfiguration; import com.intellij.openapi.vcs.IssueNavigationLink; import com.intellij.pom.java.LanguageLevel; @@ -38,7 +37,6 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase { @Override protected void setUp() throws Exception { super.setUp(); - LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.HIGHEST); myInspection = new JavaDocLocalInspection(); myInspection.setIgnoreDuplicatedThrows(false); enableInspectionTools(myInspection, new JavaDocReferenceInspection()); @@ -76,12 +74,12 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase { public void testException3() { doTest(); } public void testException4() { myInspection.METHOD_OPTIONS.ACCESS_JAVADOC_REQUIRED_FOR = "package"; doTest(); } public void testMultipleThrows() { doTest(); } - public void testInheritJavaDoc() { doTestWithLangLevel(LanguageLevel.JDK_1_3); } + public void testInheritJavaDoc() { setLanguageLevel(LanguageLevel.JDK_1_3); doTest(); } public void testLink0() { doTest(); } public void testLinkFromInnerClassToSelfMethod() { doTest(); } public void testValueBadReference() { doTest(); } public void testValueGoodReference() { doTest(); } - public void testValueReference14() { doTestWithLangLevel(LanguageLevel.JDK_1_4); } + public void testValueReference14() { setLanguageLevel(LanguageLevel.JDK_1_4); doTest(); } public void testValueEmpty() { doTest(); } public void testValueNotOnField() { doTest(); } public void testValueNotOnStaticField() { doTest(); } @@ -140,12 +138,7 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase { assertEquals(expected, refs.stream().map(PsiReferenceBase::getCanonicalText).collect(Collectors.toSet())); } - private void doTestWithLangLevel(LanguageLevel level) { - LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(level); - doTest(); - } - protected void doTest() { - super.doTest(getTestName(false) + ".java", true, false); + doTest(getTestName(false) + ".java", true, false); } } \ No newline at end of file From 1bc47c4d3e892a6d6575d1012eaa3d99296769f2 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 7 Apr 2017 16:47:00 +0300 Subject: [PATCH 095/111] publish proper course language to stepik --- .../com/jetbrains/edu/learning/StudyUtils.java | 2 +- .../stepic/EduAdaptiveStepicConnector.java | 2 +- .../learning/stepic/EduStepicConnector.java | 18 +++++++++++++++++- .../edu/learning/stepic/EduStepicNames.java | 2 ++ .../edu/learning/stepic/StepicWrappers.java | 1 + 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/python/educational-core/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/src/com/jetbrains/edu/learning/StudyUtils.java index c12b44757ee6..46d3ca1b1fc2 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/StudyUtils.java @@ -692,7 +692,7 @@ public class StudyUtils { } public static void registerStudyToolWindow(@Nullable final Course course, Project project) { - if (course != null && "PyCharm".equals(course.getCourseType())) { + if (course != null && EduNames.PYCHARM.equals(course.getCourseType())) { final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project); registerToolWindows(toolWindowManager, project); final ToolWindow studyToolWindow = toolWindowManager.getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW); diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java index f94ecb071d2e..d1da82314213 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduAdaptiveStepicConnector.java @@ -147,7 +147,7 @@ public class EduAdaptiveStepicConnector { else if (stepType.equals(CHOICE_TYPE_TEXT)) { return getChoiceTaskFromStep(name, step.block, stepId, userId); } - else if (stepType.startsWith(EduStepicConnector.PYCHARM_PREFIX)) { + else if (stepType.startsWith(EduStepicNames.PYCHARM_PREFIX)) { return EduStepicConnector.createTask(stepId); } else if (stepType.equals(TEXT_STEP_TYPE)) { diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java index 185e53613d4c..1a3adeb35fa2 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java @@ -2,13 +2,16 @@ package com.jetbrains.edu.learning.stepic; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.intellij.lang.LanguageExtensionPoint; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.edu.learning.EduPluginConfigurator; import com.jetbrains.edu.learning.StudySettings; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.*; @@ -33,12 +36,13 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.*; +import static com.jetbrains.edu.learning.stepic.EduStepicNames.PYCHARM_PREFIX; + public class EduStepicConnector { private static final Logger LOG = Logger.getInstance(EduStepicConnector.class.getName()); public static final int CURRENT_VERSION = 2; //this prefix indicates that course can be opened by educational plugin - public static final String PYCHARM_PREFIX = "pycharm"; private static final String ADAPTIVE_NOTE = "\n\nInitially, the adaptive system may behave somewhat randomly, but the more problems you solve, the smarter it becomes!"; @@ -170,8 +174,20 @@ public class EduStepicConnector { return true; } String courseType = courseInfo.getType(); + + final ArrayList supportedLanguages = new ArrayList<>(); + final LanguageExtensionPoint[] extensions = Extensions.getExtensions(EduPluginConfigurator.EP_NAME, null); + for (LanguageExtensionPoint extension : extensions) { + String languageId = extension.getKey(); + supportedLanguages.add(languageId); + } + final List typeLanguage = StringUtil.split(courseType, " "); String prefix = typeLanguage.get(0); + if (typeLanguage.size() > 1) { + final String courseLanguage = typeLanguage.get(typeLanguage.size() - 1); + if (!supportedLanguages.contains(courseLanguage)) return false; + } if (typeLanguage.size() < 2 || !prefix.startsWith(PYCHARM_PREFIX)) { return false; } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicNames.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicNames.java index b25e80fcea34..5ee99dc6cde8 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicNames.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicNames.java @@ -21,4 +21,6 @@ public class EduStepicNames { public static final String SECTIONS = "/sections/"; public static final String ENROLLMENTS = "/enrollments"; public static final String STEPIC_REGISTRATION_LINK = "https://stepic.org/registration?next=%2Fexplore%2Fcourses"; + + public static final String PYCHARM_PREFIX = "pycharm"; } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java index e7d1eefcdd91..5124acab9833 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/StepicWrappers.java @@ -194,6 +194,7 @@ public class StepicWrappers { public CourseWrapper(Course course) { this.course = new RemoteCourse(); this.course.setName(course.getName()); + this.course.setLanguage(course.getLanguageID()); this.course.setDescription(course.getDescription()); this.course.setAuthors(course.getAuthors()); } From 669a3e5a67f9fff3082abaa1ddafbf7164af75b2 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 7 Apr 2017 19:49:48 +0300 Subject: [PATCH 096/111] full support for stepik in kotlin-java courses --- .../com/jetbrains/edu/learning/Stepik.png | Bin 0 -> 228 bytes .../com/jetbrains/edu/learning/Stepik@2x.png | Bin 0 -> 290 bytes .../learning/courseFormat/RemoteCourse.java | 13 ++- .../StudyProjectGenerator.java | 2 +- .../intellij/EduIntelliJTemplateFactory.java | 28 +++++- .../stepik/EduRemoteCourseModuleBuilder.java | 90 ++++++++++++++++++ .../stepik/EduRemoteCourseTemplate.java | 48 ++++++++++ .../learning/stepic/EduStepicConnector.java | 35 ++++--- .../src/icons/EducationalCoreIcons.java | 1 + 9 files changed, 198 insertions(+), 19 deletions(-) create mode 100644 python/educational-core/resources/icons/com/jetbrains/edu/learning/Stepik.png create mode 100644 python/educational-core/resources/icons/com/jetbrains/edu/learning/Stepik@2x.png create mode 100644 python/educational-core/src/com/jetbrains/edu/learning/intellij/stepik/EduRemoteCourseModuleBuilder.java create mode 100644 python/educational-core/src/com/jetbrains/edu/learning/intellij/stepik/EduRemoteCourseTemplate.java diff --git a/python/educational-core/resources/icons/com/jetbrains/edu/learning/Stepik.png b/python/educational-core/resources/icons/com/jetbrains/edu/learning/Stepik.png new file mode 100644 index 0000000000000000000000000000000000000000..299f0d9797194cf89db52ce8041f344a34f6d79a GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFP2=EDURdQ8IJCl}lJn8@c|Ciri z?!4X!l)(d@ZPAhiN;8%O`2{mLJiCzwckjvoxzpWJ7|%vXU|`b0LR+SiyYBc<9wH$6O#=0-TTpV)vubM v?4CSRO=jcgB@YjMJU98-&rj!4)!FLz@V1NXn#)i*3*<6SS3j3^P6Z*$CLj5|9|=Y z<<9G!wdd@Q0A(3Vg8YIR9G=}s196hP-CY0cR)MV6txt;Ds#X-8 ds(NF>-?&sc^xxCmxj;uTc)I$ztaD0e0suFJWFP " - @SerializedName("course_format") private String myType = "pycharm" + EduStepicConnector.CURRENT_VERSION + " " + getLanguageID(); + @SerializedName("course_format") private String myType = + String.format("%s%d %s", EduStepicNames.PYCHARM_PREFIX, EduStepicConnector.CURRENT_VERSION, getLanguageID()); @SerializedName("is_idea_compatible") private boolean isCompatible = true; List sections; List instructors = new ArrayList<>(); @@ -31,6 +33,11 @@ public class RemoteCourse extends Course { return myType; } + public void setLanguage(@NotNull final String language) { + super.setLanguage(language); + updateType(language); + } + public List getSections() { return sections; } @@ -107,8 +114,10 @@ public class RemoteCourse extends Course { public void copyCourseParameters(RemoteCourse course) { setName(course.getName()); - setUpdateDate(course.getUpdateDate()); + } + private void updateType(String language) { + myType = String.format("%s%d %s", EduStepicNames.PYCHARM_PREFIX, EduStepicConnector.CURRENT_VERSION, language); } } diff --git a/python/educational-core/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java b/python/educational-core/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java index b294e5d29dad..6b25be65eef2 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/courseGeneration/StudyProjectGenerator.java @@ -144,7 +144,7 @@ public class StudyProjectGenerator { } @NotNull - public List getCoursesUnderProgress(boolean force, @NotNull final String progressTitle, @NotNull final Project project) { + public List getCoursesUnderProgress(boolean force, @NotNull final String progressTitle, @Nullable final Project project) { try { return ProgressManager.getInstance() .runProcessWithProgressSynchronously(() -> { diff --git a/python/educational-core/src/com/jetbrains/edu/learning/intellij/EduIntelliJTemplateFactory.java b/python/educational-core/src/com/jetbrains/edu/learning/intellij/EduIntelliJTemplateFactory.java index 48e9ce41923b..19535068e1c1 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/intellij/EduIntelliJTemplateFactory.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/intellij/EduIntelliJTemplateFactory.java @@ -3,16 +3,35 @@ package com.jetbrains.edu.learning.intellij; import com.intellij.icons.AllIcons; import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.platform.ProjectTemplate; import com.intellij.platform.ProjectTemplatesFactory; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseGeneration.StudyProjectGenerator; +import com.jetbrains.edu.learning.intellij.stepik.EduRemoteCourseTemplate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; @SuppressWarnings("unused") //used in other educational plugins that are stored in separate repository public class EduIntelliJTemplateFactory extends ProjectTemplatesFactory { private static final String GROUP_NAME = "Education"; + private static List ourRemoteCourses; + + static { + ProgressManager.getInstance().run(new Task.Backgroundable(null, "Updating Course") { + @Override + public void run(@NotNull ProgressIndicator indicator) { + ourRemoteCourses = new StudyProjectGenerator().getCourses(true); + } + }); + } @NotNull @Override @@ -23,7 +42,14 @@ public class EduIntelliJTemplateFactory extends ProjectTemplatesFactory { @NotNull @Override public ProjectTemplate[] createTemplates(@Nullable String group, WizardContext context) { - return ApplicationManager.getApplication().getExtensions(EduIntelliJProjectTemplate.EP_NAME); + final ArrayList templates = new ArrayList<>(); + if (ourRemoteCourses != null) { + for (Course course : ourRemoteCourses) { + templates.add(new EduRemoteCourseTemplate(course)); + } + } + Collections.addAll(templates, ApplicationManager.getApplication().getExtensions(EduIntelliJProjectTemplate.EP_NAME)); + return templates.toArray(new ProjectTemplate[templates.size()]); } @Override diff --git a/python/educational-core/src/com/jetbrains/edu/learning/intellij/stepik/EduRemoteCourseModuleBuilder.java b/python/educational-core/src/com/jetbrains/edu/learning/intellij/stepik/EduRemoteCourseModuleBuilder.java new file mode 100644 index 000000000000..9aa0282e7985 --- /dev/null +++ b/python/educational-core/src/com/jetbrains/edu/learning/intellij/stepik/EduRemoteCourseModuleBuilder.java @@ -0,0 +1,90 @@ +package com.jetbrains.edu.learning.intellij.stepik; + +import com.intellij.ide.util.projectWizard.JavaModuleBuilder; +import com.intellij.ide.util.projectWizard.ModuleWizardStep; +import com.intellij.ide.util.projectWizard.ProjectWizardStepFactory; +import com.intellij.ide.util.projectWizard.SettingsStep; +import com.intellij.lang.Language; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.module.ModifiableModuleModel; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleWithNameAlreadyExists; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Conditions; +import com.intellij.openapi.util.InvalidDataException; +import com.jetbrains.edu.learning.EduPluginConfigurator; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.intellij.generation.EduProjectGenerator; +import org.jdom.JDOMException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; + +class EduRemoteCourseModuleBuilder extends JavaModuleBuilder { + private static final Logger LOG = Logger.getInstance(EduRemoteCourseModuleBuilder.class); + private final Course myCourse; + private EduProjectGenerator myGenerator = new EduProjectGenerator(); + + public EduRemoteCourseModuleBuilder(Course course) { + myCourse = course; + } + + @Nullable + @Override + public Module commitModule(@NotNull Project project, @Nullable ModifiableModuleModel model) { + Module module = super.commitModule(project, model); + if (module == null) { + return null; + } + String languageName = myCourse.getLanguageID(); + Language language = Language.findLanguageByID(languageName); + if (language == null) { + return module; + } + EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(language); + if (configurator == null) { + return module; + } + configurator.configureModule(module); + return module; + } + + @Nullable + @Override + public String getBuilderId() { + return "remote.course.builder." + myCourse.getName(); + } + + @Nullable + @Override + public ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep) { + return ProjectWizardStepFactory.getInstance().createJavaSettingsStep(settingsStep, this, Conditions.alwaysTrue()); + } + + @NotNull + @Override + public Module createModule(@NotNull ModifiableModuleModel moduleModel) + throws InvalidDataException, IOException, ModuleWithNameAlreadyExists, JDOMException, ConfigurationException { + Module baseModule = super.createModule(moduleModel); + String languageName = myCourse.getLanguageID(); + Language language = Language.findLanguageByID(languageName); + if (language != null) { + EduPluginConfigurator configurator = EduPluginConfigurator.INSTANCE.forLanguage(language); + if (configurator != null) { + Project project = baseModule.getProject(); + myGenerator.setSelectedCourse(myCourse); + myGenerator.generateProject(project, project.getBaseDir()); + Course course = StudyTaskManager.getInstance(project).getCourse(); + if (course == null) { + LOG.info("failed to generate course"); + return baseModule; + } + configurator.createCourseModuleContent(moduleModel, project, course, getModuleFileDirectory()); + } + } + return baseModule; + } +} diff --git a/python/educational-core/src/com/jetbrains/edu/learning/intellij/stepik/EduRemoteCourseTemplate.java b/python/educational-core/src/com/jetbrains/edu/learning/intellij/stepik/EduRemoteCourseTemplate.java new file mode 100644 index 000000000000..b3f1bd994e10 --- /dev/null +++ b/python/educational-core/src/com/jetbrains/edu/learning/intellij/stepik/EduRemoteCourseTemplate.java @@ -0,0 +1,48 @@ +package com.jetbrains.edu.learning.intellij.stepik; + +import com.intellij.ide.util.projectWizard.AbstractModuleBuilder; +import com.intellij.openapi.ui.ValidationInfo; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.intellij.EduIntelliJProjectTemplate; +import icons.EducationalCoreIcons; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +public class EduRemoteCourseTemplate implements EduIntelliJProjectTemplate { + private final Course myCourse; + + public EduRemoteCourseTemplate(Course course) { + myCourse = course; + } + + @NotNull + @Override + public String getName() { + return myCourse.getName(); + } + + @Nullable + @Override + public String getDescription() { + return myCourse.getDescription(); + } + + @Override + public Icon getIcon() { + return EducationalCoreIcons.Stepik; + } + + @NotNull + @Override + public AbstractModuleBuilder createModuleBuilder() { + return new EduRemoteCourseModuleBuilder(myCourse); + } + + @Nullable + @Override + public ValidationInfo validateSettings() { + return null; + } +} diff --git a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java index 1a3adeb35fa2..5ae616d81654 100644 --- a/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java +++ b/python/educational-core/src/com/jetbrains/edu/learning/stepic/EduStepicConnector.java @@ -152,6 +152,8 @@ public class EduStepicConnector { final List courses = coursesContainer.courses; for (RemoteCourse info : courses) { if (!info.isAdaptive() && StringUtil.isEmptyOrSpaces(info.getType())) continue; + setCourseLanguage(info); + if (canBeOpened(info)) { final ArrayList authors = new ArrayList<>(); for (Integer instructor : info.getInstructors()) { @@ -169,12 +171,19 @@ public class EduStepicConnector { } } - static boolean canBeOpened(RemoteCourse courseInfo) { - if (courseInfo.isAdaptive()) { - return true; + private static void setCourseLanguage(RemoteCourse info) { + if (info.isAdaptive()) { + info.setLanguage("Python"); // adaptive courses available only in PyCharm now + return; } - String courseType = courseInfo.getType(); + String courseType = info.getType(); + final int separator = courseType.indexOf(" "); + assert separator != -1; + final String language = courseType.substring(separator + 1); + info.setLanguage(language); + } + static boolean canBeOpened(RemoteCourse courseInfo) { final ArrayList supportedLanguages = new ArrayList<>(); final LanguageExtensionPoint[] extensions = Extensions.getExtensions(EduPluginConfigurator.EP_NAME, null); for (LanguageExtensionPoint extension : extensions) { @@ -182,12 +191,14 @@ public class EduStepicConnector { supportedLanguages.add(languageId); } + if (courseInfo.isAdaptive()) { + return supportedLanguages.contains(courseInfo.getLanguageID()); + } + + String courseType = courseInfo.getType(); final List typeLanguage = StringUtil.split(courseType, " "); String prefix = typeLanguage.get(0); - if (typeLanguage.size() > 1) { - final String courseLanguage = typeLanguage.get(typeLanguage.size() - 1); - if (!supportedLanguages.contains(courseLanguage)) return false; - } + if (!supportedLanguages.contains(courseInfo.getLanguageID())) return false; if (typeLanguage.size() < 2 || !prefix.startsWith(PYCHARM_PREFIX)) { return false; } @@ -205,14 +216,8 @@ public class EduStepicConnector { } } - public static RemoteCourse getCourse(@NotNull final Project project, @NotNull final RemoteCourse course) { - final RemoteCourse remoteCourse = (RemoteCourse)course.copy(); + public static RemoteCourse getCourse(@NotNull final Project project, @NotNull final RemoteCourse remoteCourse) { if (!remoteCourse.isAdaptive()) { - String courseType = remoteCourse.getType(); - final int separator = courseType.indexOf(" "); - assert separator != -1; - final String language = courseType.substring(separator + 1); - remoteCourse.setLanguage(language); try { for (Integer section : remoteCourse.getSections()) { remoteCourse.addLessons(getLessons(section)); diff --git a/python/educational-core/src/icons/EducationalCoreIcons.java b/python/educational-core/src/icons/EducationalCoreIcons.java index c089db48d76c..73c105a44024 100644 --- a/python/educational-core/src/icons/EducationalCoreIcons.java +++ b/python/educational-core/src/icons/EducationalCoreIcons.java @@ -22,6 +22,7 @@ public class EducationalCoreIcons { public static final Icon ResetTaskFile = load("/icons/com/jetbrains/edu/learning/ResetTaskFile.png"); // 16x16 public static final Icon Sandbox = load("/icons/com/jetbrains/edu/learning/Sandbox.png"); // 16x16 public static final Icon ShowHint = load("/icons/com/jetbrains/edu/learning/showHint.png"); // 16x16 + public static final Icon Stepik = load("/icons/com/jetbrains/edu/learning/Stepik.png"); // 16x16 public static final Icon Task = load("/icons/com/jetbrains/edu/learning/Task.png"); // 16x16 public static final Icon TaskCompl = load("/icons/com/jetbrains/edu/learning/TaskCompl.png"); // 16x16 public static final Icon TaskDescription = load("/icons/com/jetbrains/edu/learning/TaskDescription.png"); // 13x13 From fae23a3f61ebfcbdc6578dff0feaf3dcff7c71f5 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 7 Apr 2017 18:53:04 +0200 Subject: [PATCH 097/111] [java] drops extra quotes from "disallowed tag" warning --- .../src/messages/InspectionsBundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index 0105b1969d71..8ce66459e6a1 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -288,7 +288,7 @@ inspection.javadoc.problem.see.tag.expecting.ref=Class/method reference, quoted inspection.javadoc.problem.cannot.resolve=Cannot resolve symbol {0} inspection.javadoc.problem.name.expected=Name expected inspection.javadoc.problem.wrong.tag=Wrong tag {0} -inspection.javadoc.problem.disallowed.tag=Tag ''{0}'' is not allowed here +inspection.javadoc.problem.disallowed.tag=Tag {0} is not allowed here inspection.javadoc.method.problem.descriptor=Description is missing in {0} tag for parameter {1} inspection.javadoc.method.problem.missing.tag.description={0} tag description is missing inspection.javadoc.method.problem.missing.param.tag=Required tag @param is missing for parameter {0} From 0588a4d12cacc3c6900729fa36350611b7514d22 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 7 Apr 2017 18:53:56 +0200 Subject: [PATCH 098/111] [java] recognizes @moduleGraph tag --- .../psi/impl/source/javadoc/JavadocManagerImpl.java | 3 ++- .../daemonCodeAnalyzer/javaDoc/Java18Tags.java | 13 +++++++------ .../daemonCodeAnalyzer/javaDoc/module-info.java | 5 +++++ .../codeInsight/daemon/JavadocHighlightingTest.java | 1 + 4 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/module-info.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/JavadocManagerImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/JavadocManagerImpl.java index a5d63a7ce89f..5e4153c05211 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/JavadocManagerImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/javadoc/JavadocManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2016 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -48,6 +48,7 @@ public class JavadocManagerImpl implements JavadocManager { myInfos.add(new SimpleDocTagInfo("apiNote", LanguageLevel.JDK_1_8, false, PsiElement.class)); myInfos.add(new SimpleDocTagInfo("implNote", LanguageLevel.JDK_1_8, false, PsiElement.class)); myInfos.add(new SimpleDocTagInfo("implSpec", LanguageLevel.JDK_1_8, false, PsiElement.class)); + myInfos.add(new SimpleDocTagInfo("moduleGraph", LanguageLevel.JDK_1_9, false, PsiJavaModule.class)); myInfos.add(new SimpleDocTagInfo("docRoot", LanguageLevel.JDK_1_3, true, PsiElement.class)); myInfos.add(new SimpleDocTagInfo("inheritDoc", LanguageLevel.JDK_1_4, true, PsiElement.class)); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Java18Tags.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Java18Tags.java index 80a6789e8f50..1f0554cf80e2 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Java18Tags.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/Java18Tags.java @@ -1,8 +1,9 @@ class Test { - /** - * @apiNote note1 - * @implNote implNote - * @implSpec implSpec - */ - public void i() {} + /** + * @apiNote note1 + * @implNote implNote + * @implSpec implSpec + * @moduleGraph + */ + public void i() {} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/module-info.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/module-info.java new file mode 100644 index 000000000000..c28f08182edc --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/javaDoc/module-info.java @@ -0,0 +1,5 @@ +/** + * @moduleGraph + * @since 9 + */ +module Test { } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java index f563d896978f..5ccc1e7e440a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/JavadocHighlightingTest.java @@ -107,6 +107,7 @@ public class JavadocHighlightingTest extends LightDaemonAnalyzerTestCase { public void testIgnoreDuplicateThrows() { myInspection.setIgnoreDuplicatedThrows(true); doTest(); } public void testIgnoreAccessors() { myInspection.setIgnoreSimpleAccessors(true); doTest(); } public void testAuthoredMethod() { doTest(); } + public void testModuleTags() { doTest("module-info.java", true, false); } public void testIssueLinksInJavaDoc() { IssueNavigationConfiguration navigationConfiguration = IssueNavigationConfiguration.getInstance(getProject()); From f623b2b302c6c24f31fd0e6cc45d9cf2de169f6a Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 7 Apr 2017 18:54:12 +0200 Subject: [PATCH 099/111] Cleanup (warnings) --- .../intellij/codeInspection/javaDoc/JavadocHighlightUtil.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavadocHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavadocHighlightUtil.java index 90d0d9c261c7..ee93d1e8e5de 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavadocHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/javaDoc/JavadocHighlightUtil.java @@ -46,6 +46,7 @@ public class JavadocHighlightUtil { private static final TokenSet SEE_TAG_REFS = TokenSet.create( JavaDocElementType.DOC_REFERENCE_HOLDER, JavaDocElementType.DOC_METHOD_OR_FIELD_REF); + @SuppressWarnings("SameParameterValue") public interface ProblemHolder { Project project(); JavaDocLocalInspectionBase inspection(); From 506175911b5d19828d6e5c9230b951501bf62433 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 7 Apr 2017 19:55:52 +0300 Subject: [PATCH 100/111] removed obsolete dependencies from edu --- python/educational-python/Edu-Python/Edu-Python.iml | 1 - python/educational-python/main_pycharm_edu.iml | 1 - 2 files changed, 2 deletions(-) diff --git a/python/educational-python/Edu-Python/Edu-Python.iml b/python/educational-python/Edu-Python/Edu-Python.iml index 815befd49b4b..919047b0072a 100644 --- a/python/educational-python/Edu-Python/Edu-Python.iml +++ b/python/educational-python/Edu-Python/Edu-Python.iml @@ -13,7 +13,6 @@ - \ No newline at end of file diff --git a/python/educational-python/main_pycharm_edu.iml b/python/educational-python/main_pycharm_edu.iml index 8a0ded56714a..4f0645b39f2e 100644 --- a/python/educational-python/main_pycharm_edu.iml +++ b/python/educational-python/main_pycharm_edu.iml @@ -15,7 +15,6 @@ - From 1d95e4ee02add4e9ef48e89f4fe20e57265e423a Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 7 Apr 2017 18:55:48 +0200 Subject: [PATCH 101/111] java 9: effectively final check fixed (IDEA-171152) --- .../codeInsight/daemon/impl/analysis/HighlightUtil.java | 8 +------- .../advHighlighting9/TryWithResources.java | 3 ++- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index edaf4e6391c8..6aeb04a5bbf9 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -1798,13 +1798,7 @@ public class HighlightUtil extends HighlightUtilBase { PsiModifierList modifierList = variable.getModifierList(); if (modifierList != null && modifierList.hasModifierProperty(PsiModifier.FINAL)) return null; - PsiElement scope = null; - if (variable instanceof PsiParameter) scope = ((PsiParameter)variable).getDeclarationScope(); - else if (variable instanceof PsiResourceVariable) scope = variable.getParent().getParent(); - else if (variable instanceof PsiLocalVariable) scope = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); - if (scope != null) { - if (HighlightControlFlowUtil.isEffectivelyFinal(variable, scope, null)) return null; - } + if (!(variable instanceof PsiField) && HighlightControlFlowUtil.isEffectivelyFinal(variable, resource, (PsiJavaCodeReferenceElement)expression)) return null; } String text = JavaErrorMessages.message("resource.variable.must.be.final"); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting9/TryWithResources.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting9/TryWithResources.java index e7665f8facda..753fe56ffa90 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting9/TryWithResources.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting9/TryWithResources.java @@ -13,7 +13,8 @@ class TryWithResources { final AutoCloseable r1 = null; AutoCloseable r2 = null; AutoCloseable r3 = null; - try (r1; r2; r3) { } + AutoCloseable r4; r4 = null; + try (r1; r2; r4; r3) { } r3 = null; } From b1138fe35945fe0a6e81f9ed512d680b519c6121 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 7 Apr 2017 19:27:02 +0200 Subject: [PATCH 102/111] don't merge different descriptions at same start offset --- .../intellij/codeInspection/CommonProblemDescriptor.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/analysis-api/src/com/intellij/codeInspection/CommonProblemDescriptor.java b/platform/analysis-api/src/com/intellij/codeInspection/CommonProblemDescriptor.java index 11576b10d4e1..4ca0126c1842 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/CommonProblemDescriptor.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/CommonProblemDescriptor.java @@ -36,8 +36,11 @@ public interface CommonProblemDescriptor { if (diff != 0) { return diff; } - return PsiUtilCore.compareElementsByPosition(((ProblemDescriptor)c2).getPsiElement(), - ((ProblemDescriptor)c1).getPsiElement()); + + diff = PsiUtilCore.compareElementsByPosition(((ProblemDescriptor)c2).getPsiElement(), ((ProblemDescriptor)c1).getPsiElement()); + if (diff != 0) { + return diff; + } } return c1.getDescriptionTemplate().compareTo(c2.getDescriptionTemplate()); }; From 9ef3a2b3a4162440324134e3cbe6190cf1e55b15 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 7 Apr 2017 20:33:46 +0300 Subject: [PATCH 103/111] Don't show non-public names from buitlins stub in completion (PY-22828) The Typeshed stub from buitlins contains several non-public names: * Imports from other modules * Protected names (_foo) --- .../psi/impl/references/PyReferenceImpl.java | 16 ++++++++++++++-- .../PythonBuiltinReferenceResolveProvider.java | 2 +- .../noProtectedBuiltinNames.py | 3 +++ .../jetbrains/python/PythonCompletionTest.java | 16 ++++++++++++++++ .../PyUnresolvedReferencesInspectionTest.java | 5 +++++ 5 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/noProtectedBuiltinNames.py diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java index 05dc987be1ef..451a1db5b390 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -637,7 +637,19 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference // include our own names final int underscores = PyUtil.getInitialUnderscores(element.getName()); - final CompletionVariantsProcessor processor = new CompletionVariantsProcessor(element); + final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(element); + final CompletionVariantsProcessor processor = new CompletionVariantsProcessor(element, e -> { + if (builtinCache.isBuiltin(e)) { + final String name = e instanceof PyElement ? ((PyElement)e).getName() : null; + if (e instanceof PyImportElement) { + return false; + } + if (name != null && PyUtil.getInitialUnderscores(name) == 1) { + return false; + } + } + return true; + }, null); final ScopeOwner owner = realContext instanceof ScopeOwner ? (ScopeOwner)realContext : ScopeUtil.getScopeOwner(realContext); if (owner != null) { PyResolveUtil.scopeCrawlUp(processor, owner, null, null); @@ -648,7 +660,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference KeywordArgumentCompletionUtil.collectFunctionArgNames(element, ret, TypeEvalContext.codeCompletion(element.getProject(), element.getContainingFile())); // include builtin names - final PyFile builtinsFile = PyBuiltinCache.getInstance(element).getBuiltinsFile(); + final PyFile builtinsFile = builtinCache.getBuiltinsFile(); if (builtinsFile != null) { PyResolveUtil.scopeCrawlUp(processor, builtinsFile, null, null); } diff --git a/python/src/com/jetbrains/python/psi/resolve/PythonBuiltinReferenceResolveProvider.java b/python/src/com/jetbrains/python/psi/resolve/PythonBuiltinReferenceResolveProvider.java index 1dab95b9fd11..b1dcd9b58840 100644 --- a/python/src/com/jetbrains/python/psi/resolve/PythonBuiltinReferenceResolveProvider.java +++ b/python/src/com/jetbrains/python/psi/resolve/PythonBuiltinReferenceResolveProvider.java @@ -59,7 +59,7 @@ public class PythonBuiltinReferenceResolveProvider implements PyReferenceResolve // ...as a builtin symbol final PyFile builtinsFile = builtinCache.getBuiltinsFile(); - if (builtinsFile != null && !PyUtil.isClassPrivateName(referencedName)) { + if (builtinsFile != null && !PyUtil.isClassPrivateName(referencedName) && PyUtil.getInitialUnderscores(referencedName) != 1) { for (RatedResolveResult resolveResult : builtinsFile.multiResolveName(referencedName)) { result.add(new ImportedResolveResult(resolveResult.getElement(), resolveResult.getRate(), null)); } diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/noProtectedBuiltinNames.py b/python/testData/inspections/PyUnresolvedReferencesInspection/noProtectedBuiltinNames.py new file mode 100644 index 000000000000..bab889cd914e --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/noProtectedBuiltinNames.py @@ -0,0 +1,3 @@ +print(_T, _KT) +print(__import__) +print(len) diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java index 6e66e1a7d0d8..70a901b1cd16 100644 --- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java @@ -1114,6 +1114,22 @@ public class PythonCompletionTest extends PyTestCase { assertSameElements(variants, "mod1", "mod2", "foo", "_bar"); } + // PY-22828 + public void testNoImportedBuiltinNames() { + final List suggested = doTestByText("T\n"); + assertNotNull(suggested); + assertContainsElements(suggested, "TypeError"); + assertDoesntContain(suggested, "TypeVar"); + } + + // PY-22828 + public void testNoProtectedBuiltinNames() { + final List suggested = doTestByText("_\n"); + assertNotNull(suggested); + assertContainsElements(suggested, "__import__"); + assertDoesntContain(suggested, "_T", "_KT"); + } + @Override protected String getTestDataPath() { return super.getTestDataPath() + "/completion"; diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 0b4da8a34b8e..e26d550b25ed 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -763,6 +763,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { doTest(); } + // PY-22828 + public void testNoProtectedBuiltinNames() { + doTest(); + } + @NotNull @Override protected Class getInspectionClass() { From 7f0cdcfa492cfdcbfe3ab27bacf3ef1b8a9f9282 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Fri, 7 Apr 2017 20:32:46 +0300 Subject: [PATCH 104/111] [groovy] don't call clazz.getText() (IDEA-165664) --- .../untypedUnresolvedAccess/GrUnresolvedAccessChecker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GrUnresolvedAccessChecker.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GrUnresolvedAccessChecker.java index dd31e7609d48..efaa81eba912 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GrUnresolvedAccessChecker.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/untypedUnresolvedAccess/GrUnresolvedAccessChecker.java @@ -166,7 +166,7 @@ public class GrUnresolvedAccessChecker { !PsiUtil.hasEnclosingInstanceInScope(outerClass, newExpression, true) && !hasEnclosingInstanceInArgList(newExpression.getArgumentList(), outerClass)) { String qname = clazz.getQualifiedName(); - LOG.assertTrue(qname != null, clazz.getText()); + LOG.assertTrue(qname != null); return createAnnotationForRef(refElement, inStaticContext, GroovyBundle.message("cannot.reference.non.static", qname)); } } From 4c3356ae3e477ac0a0ed00c446728c56b6c337e8 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Fri, 7 Apr 2017 19:48:39 +0200 Subject: [PATCH 105/111] push condition: fix endless loop --- .../src/com/siyeh/ig/psiutils/EquivalenceChecker.java | 3 +++ .../ConditionalExpressionWithIdenticalBranches.java | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/EquivalenceChecker.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/EquivalenceChecker.java index 3da752ad75a4..2ac909480b7c 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/EquivalenceChecker.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/EquivalenceChecker.java @@ -651,6 +651,9 @@ public class EquivalenceChecker { else if (statement instanceof PsiBlockStatement) { element = ((PsiBlockStatement)statement).getCodeBlock(); } + else { + break; + } } return element; } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/conditional_expression_with_identical_branches/ConditionalExpressionWithIdenticalBranches.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/conditional_expression_with_identical_branches/ConditionalExpressionWithIdenticalBranches.java index db8441944e35..3ff85e074494 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/conditional_expression_with_identical_branches/ConditionalExpressionWithIdenticalBranches.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/controlflow/conditional_expression_with_identical_branches/ConditionalExpressionWithIdenticalBranches.java @@ -39,6 +39,10 @@ class ConditionalExpressionWithIdenticalBranches { } } + void lambdaCycle(boolean b){ + Runnable r = b ? () -> {if (true);} : () -> {if (true);}; + } + interface IntSupplier { int getAsInt(); } From 873ae2e4eebe771a312510603b264484bcad024f Mon Sep 17 00:00:00 2001 From: Artem Khvastunov Date: Fri, 7 Apr 2017 12:00:23 +0200 Subject: [PATCH 106/111] @Nullable -> @Contract("null -> null") for StringRef (cherry picked from commit 2d7f630992e2b72d10b078f3ff3caf4f452f5625) --- platform/util/src/com/intellij/util/io/StringRef.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/util/src/com/intellij/util/io/StringRef.java b/platform/util/src/com/intellij/util/io/StringRef.java index dec7bef2db70..7cbfbecb0dbd 100644 --- a/platform/util/src/com/intellij/util/io/StringRef.java +++ b/platform/util/src/com/intellij/util/io/StringRef.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2017 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. @@ -15,6 +15,7 @@ */ package com.intellij.util.io; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -92,12 +93,12 @@ public class StringRef { return that == this || that instanceof StringRef && toString().equals(that.toString()); } - @Nullable + @Contract("null -> null") public static String toString(@Nullable StringRef ref) { return ref != null ? ref.getString() : null; } - @Nullable + @Contract("null -> null; !null -> !null") public static StringRef fromString(@Nullable String source) { return source == null ? null : new StringRef(source); } From 1523362af7651ee7c34d4049d63735b5bc6d66bd Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Fri, 7 Apr 2017 22:46:09 +0300 Subject: [PATCH 107/111] PY-23267: Tests added to check right click on tests folder creates Django test run configuration --- .../testing/CreateConfigurationTestTask.java | 60 +++++++++++-------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/python/testSrc/com/jetbrains/env/python/testing/CreateConfigurationTestTask.java b/python/testSrc/com/jetbrains/env/python/testing/CreateConfigurationTestTask.java index 0a1a0d9a47cd..6f88bc48f25e 100644 --- a/python/testSrc/com/jetbrains/env/python/testing/CreateConfigurationTestTask.java +++ b/python/testSrc/com/jetbrains/env/python/testing/CreateConfigurationTestTask.java @@ -46,12 +46,12 @@ import java.util.Optional; * * @author Ilya.Kazakevich */ -abstract class CreateConfigurationTestTask extends PyExecutionFixtureTestTask { +public abstract class CreateConfigurationTestTask extends PyExecutionFixtureTestTask { @Nullable private final String myTestRunnerName; @NotNull - private final Class myExpectedConfigurationType; + private final Class myExpectedConfigurationType; /** * @param testRunnerName test runner name (to set as default to make sure producer launched) @@ -77,39 +77,49 @@ abstract class CreateConfigurationTestTask extends P for (final PsiElement elementToRightClickOn : getPsiElementsToRightClickOn()) { - final List configurationsFromContext = - new ConfigurationContext(elementToRightClickOn).getConfigurationsFromContext(); - Assert.assertNotNull("Producers were not able to create any configuration in " + elementToRightClickOn, configurationsFromContext); - - - final Optional maybeConfig = configurationsFromContext.stream() - .filter(o -> myExpectedConfigurationType.isAssignableFrom(o.getConfiguration().getClass())) - .findFirst(); - Assert.assertTrue("No configuration of expected type created", maybeConfig.isPresent()); - RunnerAndConfigurationSettings runnerAndConfigurationSettings = maybeConfig.get().getConfigurationSettings(); - - - Assert.assertNotNull("Producers were not able to create any configuration in " + elementToRightClickOn, runnerAndConfigurationSettings); - final RunConfiguration configuration = runnerAndConfigurationSettings.getConfiguration(); - Assert.assertNotNull("No real configuration created", configuration); - Assert.assertThat("No name for configuration", configuration.getName(), Matchers.not(Matchers.isEmptyOrNullString())); - Assert.assertThat("Bad configuration type in " + elementToRightClickOn, configuration, - Matchers.is(Matchers.instanceOf(myExpectedConfigurationType))); - - RunManager.getInstance(getProject()).addConfiguration(runnerAndConfigurationSettings, false); - @SuppressWarnings("unchecked") // Checked one line above - final T typedConfiguration = (T)configuration; + final T typedConfiguration = createConfigurationByElement(elementToRightClickOn, myExpectedConfigurationType); checkConfiguration(typedConfiguration, elementToRightClickOn); } }), ModalityState.NON_MODAL); } + /** + * Emulates right click and create configurwation + */ + @NotNull + public static T createConfigurationByElement(@NotNull final PsiElement elementToRightClickOn, + @NotNull Class expectedConfigurationType) { + final List configurationsFromContext = + new ConfigurationContext(elementToRightClickOn).getConfigurationsFromContext(); + Assert.assertNotNull("Producers were not able to create any configuration in " + elementToRightClickOn, configurationsFromContext); + + + final Optional maybeConfig = configurationsFromContext.stream() + .filter(o -> expectedConfigurationType.isAssignableFrom(o.getConfiguration().getClass())) + .findFirst(); + Assert.assertTrue("No configuration of expected type created", maybeConfig.isPresent()); + RunnerAndConfigurationSettings runnerAndConfigurationSettings = maybeConfig.get().getConfigurationSettings(); + + + Assert.assertNotNull("Producers were not able to create any configuration in " + elementToRightClickOn, runnerAndConfigurationSettings); + final RunConfiguration configuration = runnerAndConfigurationSettings.getConfiguration(); + Assert.assertNotNull("No real configuration created", configuration); + Assert.assertThat("No name for configuration", configuration.getName(), Matchers.not(Matchers.isEmptyOrNullString())); + Assert.assertThat("Bad configuration type in " + elementToRightClickOn, configuration, + Matchers.is(Matchers.instanceOf(expectedConfigurationType))); + + RunManager.getInstance(elementToRightClickOn.getProject()).addConfiguration(runnerAndConfigurationSettings, false); + + @SuppressWarnings("unchecked") // Checked one line above + final T typedConfiguration = (T)configuration; + return typedConfiguration; + } + @NotNull protected abstract List getPsiElementsToRightClickOn(); - protected void checkConfiguration(@NotNull final T configuration, @NotNull final PsiElement elementToRightClickOn) { // Configuration already checked when created, but you can do specific checks here } From 2d2d8dd4d07c34ffef237aaf92b054a9600e02e0 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 7 Apr 2017 20:38:13 +0300 Subject: [PATCH 108/111] IDEA-169924 / IDEA-166147 Middle click on breadcrumbs bar navigates to whatever is under the caret --- .../com/intellij/ui/components/breadcrumbs/Breadcrumbs.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/platform-api/src/com/intellij/ui/components/breadcrumbs/Breadcrumbs.java b/platform/platform-api/src/com/intellij/ui/components/breadcrumbs/Breadcrumbs.java index 393569045ac5..d8e478989abf 100644 --- a/platform/platform-api/src/com/intellij/ui/components/breadcrumbs/Breadcrumbs.java +++ b/platform/platform-api/src/com/intellij/ui/components/breadcrumbs/Breadcrumbs.java @@ -47,6 +47,8 @@ import java.util.function.Function; import javax.swing.JComponent; import javax.swing.border.AbstractBorder; +import static javax.swing.SwingUtilities.isLeftMouseButton; + /** * @author Sergey.Malenkov */ @@ -416,6 +418,7 @@ public class Breadcrumbs extends JComponent implements RegionPainter { if (!isHovered(crumb)) consumer = hover; break; case MouseEvent.MOUSE_CLICKED: + if (!isLeftMouseButton(event)) break; crumb = function.apply(event); if (crumb != null) consumer = select; break; From 29e8a73099eda51c30974c99c8625b83bc29bed8 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 7 Apr 2017 20:56:07 +0300 Subject: [PATCH 109/111] IDEA-169924 constant gap between breadcrumbs --- .../ui/components/breadcrumbs/Breadcrumbs.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/platform/platform-api/src/com/intellij/ui/components/breadcrumbs/Breadcrumbs.java b/platform/platform-api/src/com/intellij/ui/components/breadcrumbs/Breadcrumbs.java index d8e478989abf..50c026a2b324 100644 --- a/platform/platform-api/src/com/intellij/ui/components/breadcrumbs/Breadcrumbs.java +++ b/platform/platform-api/src/com/intellij/ui/components/breadcrumbs/Breadcrumbs.java @@ -339,6 +339,10 @@ public class Breadcrumbs extends JComponent implements RegionPainter { return insets; } + private static int getGap(Component component) { + return 10 * getScale(component); + } + private static int getScale(Component component) { return component == null ? 1 : getScale(component.getFont()); } @@ -366,7 +370,9 @@ public class Breadcrumbs extends JComponent implements RegionPainter { @Override public Dimension preferredLayoutSize(Container container) { - Dimension size = getPreferredSize(getComponents(container, Breadcrumbs::toVisible)); + ArrayList components = getComponents(container, Breadcrumbs::toVisible); + Dimension size = getPreferredSize(components); + size.width += components.size() * getGap(container); if (size.height == 0) size.height = getPreferredHeight(container); JBInsets.addTo(size, container.getInsets()); return size; @@ -387,7 +393,7 @@ public class Breadcrumbs extends JComponent implements RegionPainter { else /*if (bounds.width < size.width) { } else*/ { - int gap = Math.max(0, Math.min(10 * getScale(container), (bounds.width - size.width) / (count - 1))); + int gap = getGap(container); for (Component component : components) { Dimension preferred = component.getPreferredSize(); component.setBounds(bounds.x, bounds.y, preferred.width, bounds.height); From c71437e38b3a753191948af89dd2eaaf0cfb5878 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 7 Apr 2017 21:51:55 +0300 Subject: [PATCH 110/111] IDEA-169924 extract breadcrumbs from xml wrapper --- .../BreadcrumbsInitializingActivity.java | 4 +- .../breadcrumbs/BreadcrumbsXmlWrapper.java | 84 +---------------- .../xml/breadcrumbs/PsiBreadcrumbs.java | 90 +++++++++++++++++++ .../intellij/xml/breadcrumbs/PsiCrumb.java | 40 +++++++++ 4 files changed, 136 insertions(+), 82 deletions(-) create mode 100644 xml/impl/src/com/intellij/xml/breadcrumbs/PsiBreadcrumbs.java create mode 100644 xml/impl/src/com/intellij/xml/breadcrumbs/PsiCrumb.java diff --git a/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsInitializingActivity.java b/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsInitializingActivity.java index 4cf33566d78e..7947105d3f63 100644 --- a/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsInitializingActivity.java +++ b/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsInitializingActivity.java @@ -141,7 +141,7 @@ public class BreadcrumbsInitializingActivity implements StartupActivity, DumbAwa @NotNull FileEditor fileEditor, @NotNull BreadcrumbsXmlWrapper wrapper) { //noinspection deprecation - if (wrapper.above) { + if (wrapper.breadcrumbs.above) { fileEditorManager.addTopComponent(fileEditor, wrapper); } else { @@ -154,7 +154,7 @@ public class BreadcrumbsInitializingActivity implements StartupActivity, DumbAwa @NotNull FileEditor fileEditor, @NotNull BreadcrumbsXmlWrapper wrapper) { //noinspection deprecation - if (wrapper.above) { + if (wrapper.breadcrumbs.above) { fileEditorManager.removeTopComponent(fileEditor, wrapper); } else { diff --git a/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java b/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java index 8e5a45b8391c..6bb7a3150664 100644 --- a/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java +++ b/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java @@ -49,8 +49,6 @@ import com.intellij.openapi.vcs.FileStatusManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.ui.Gray; -import com.intellij.ui.RelativeFont; -import com.intellij.ui.components.breadcrumbs.Breadcrumbs; import com.intellij.ui.components.breadcrumbs.Crumb; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.update.MergingUpdateQueue; @@ -77,77 +75,7 @@ import static com.intellij.ui.ScrollPaneFactory.createScrollPane; * @author spleaner */ public class BreadcrumbsXmlWrapper extends JComponent implements Disposable { - private static final class PsiCrumb extends Crumb.Impl { - private final PsiElement element; - private CrumbPresentation presentation; - - private PsiCrumb(PsiElement element, BreadcrumbsInfoProvider provider) { - super(null, provider.getElementInfo(element), provider.getElementTooltip(element)); - this.element = element; - } - - private static PsiElement getElement(Crumb crumb) { - return crumb instanceof PsiCrumb ? ((PsiCrumb)crumb).element : null; - } - - private static CrumbPresentation getPresentation(Crumb crumb) { - return crumb instanceof PsiCrumb ? ((PsiCrumb)crumb).presentation : null; - } - } - - final boolean above = Registry.is("editor.breadcrumbs.above"); - - private final Breadcrumbs breadcrumbs = new Breadcrumbs() { - @Override - protected void paint(Graphics2D g, int x, int y, int width, int height, int thickness) { - super.paint(g, x, y, width, above ? height : thickness, thickness); - } - - @Override - public void setFont(Font font) { - super.setFont(RelativeFont.SMALL.derive(font)); - } - - @Override - public Color getForeground() { - if (!isForegroundSet()) { - Color foreground = EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.LINE_NUMBERS_COLOR); - if (foreground != null) return foreground; - } - return super.getForeground(); - } - - @Override - public Color getBackground() { - if (!isBackgroundSet()) { - Color background = EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.GUTTER_BACKGROUND); - if (background != null) return background; - } - return super.getBackground(); - } - - @Override - protected Color getForeground(Crumb crumb) { - CrumbPresentation presentation = PsiCrumb.getPresentation(crumb); - if (presentation == null) return super.getForeground(crumb); - - Color background = super.getBackground(crumb); - if (background != null) return super.getForeground(crumb); - - return presentation.getBackgroundColor(isSelected(crumb), isHovered(crumb), isAfterSelected(crumb)); - } - - @Override - protected Color getBackground(Crumb crumb) { - CrumbPresentation presentation = PsiCrumb.getPresentation(crumb); - if (presentation == null) return super.getBackground(crumb); - - Color background = super.getBackground(crumb); - if (background == null) return null; - - return presentation.getBackgroundColor(isSelected(crumb), isHovered(crumb), isAfterSelected(crumb)); - } - }; + final PsiBreadcrumbs breadcrumbs = new PsiBreadcrumbs(); private final static Logger LOG = Logger.getInstance(BreadcrumbsXmlWrapper.class); @@ -256,7 +184,7 @@ public class BreadcrumbsXmlWrapper extends JComponent implements Disposable { ComponentAdapter resizeListener = new ComponentAdapter() { @Override public void componentResized(ComponentEvent event) { - updateBorder(gutterComponent.getWhitespaceSeparatorOffset()); + breadcrumbs.updateBorder(gutterComponent.getWhitespaceSeparatorOffset()); } }; @@ -266,10 +194,10 @@ public class BreadcrumbsXmlWrapper extends JComponent implements Disposable { removeComponentListener(resizeListener); gutterComponent.removeComponentListener(resizeListener); }); - updateBorder(gutterComponent.getWhitespaceSeparatorOffset()); + breadcrumbs.updateBorder(gutterComponent.getWhitespaceSeparatorOffset()); } else { - updateBorder(0); + breadcrumbs.updateBorder(0); } Disposer.register(this, new UiNotifyConnector(breadcrumbs, myQueue)); Disposer.register(this, myQueue); @@ -277,10 +205,6 @@ public class BreadcrumbsXmlWrapper extends JComponent implements Disposable { queueUpdate(); } - private void updateBorder(int offset) { - breadcrumbs.setBorder(BorderFactory.createEmptyBorder(above ? 2 : 0, offset, above ? 0 : 2, 0)); - } - private void updateCrumbs() { if (breadcrumbs != null && myEditor != null && !myEditor.isDisposed()) { breadcrumbs.setFont(getEditorFont(myEditor)); diff --git a/xml/impl/src/com/intellij/xml/breadcrumbs/PsiBreadcrumbs.java b/xml/impl/src/com/intellij/xml/breadcrumbs/PsiBreadcrumbs.java new file mode 100644 index 000000000000..ce1f7cc82ed1 --- /dev/null +++ b/xml/impl/src/com/intellij/xml/breadcrumbs/PsiBreadcrumbs.java @@ -0,0 +1,90 @@ +/* + * Copyright 2000-2017 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.xml.breadcrumbs; + +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.ui.RelativeFont; +import com.intellij.ui.components.breadcrumbs.Breadcrumbs; +import com.intellij.ui.components.breadcrumbs.Crumb; + +import javax.swing.border.EmptyBorder; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; + +/** + * @author Sergey.Malenkov + */ +final class PsiBreadcrumbs extends Breadcrumbs { + final boolean above = Registry.is("editor.breadcrumbs.above"); + + void updateBorder(int offset) { + // do not use scaling here because this border is used to align breadcrumbs with a gutter + setBorder(new EmptyBorder(above ? 2 : 0, offset, above ? 0 : 2, 0)); + } + + @Override + protected void paint(Graphics2D g, int x, int y, int width, int height, int thickness) { + super.paint(g, x, y, width, above ? height : thickness, thickness); + } + + @Override + public void setFont(Font font) { + super.setFont(RelativeFont.SMALL.derive(font)); + } + + @Override + public Color getForeground() { + if (!isForegroundSet()) { + Color foreground = EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.LINE_NUMBERS_COLOR); + if (foreground != null) return foreground; + } + return super.getForeground(); + } + + @Override + public Color getBackground() { + if (!isBackgroundSet()) { + Color background = EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.GUTTER_BACKGROUND); + if (background != null) return background; + } + return super.getBackground(); + } + + @Override + protected Color getForeground(Crumb crumb) { + CrumbPresentation presentation = PsiCrumb.getPresentation(crumb); + if (presentation == null) return super.getForeground(crumb); + + Color background = super.getBackground(crumb); + if (background != null) return super.getForeground(crumb); + + return presentation.getBackgroundColor(isSelected(crumb), isHovered(crumb), isAfterSelected(crumb)); + } + + @Override + protected Color getBackground(Crumb crumb) { + CrumbPresentation presentation = PsiCrumb.getPresentation(crumb); + if (presentation == null) return super.getBackground(crumb); + + Color background = super.getBackground(crumb); + if (background == null) return null; + + return presentation.getBackgroundColor(isSelected(crumb), isHovered(crumb), isAfterSelected(crumb)); + } +} diff --git a/xml/impl/src/com/intellij/xml/breadcrumbs/PsiCrumb.java b/xml/impl/src/com/intellij/xml/breadcrumbs/PsiCrumb.java new file mode 100644 index 000000000000..247f72e001b2 --- /dev/null +++ b/xml/impl/src/com/intellij/xml/breadcrumbs/PsiCrumb.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2017 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.xml.breadcrumbs; + +import com.intellij.psi.PsiElement; +import com.intellij.ui.components.breadcrumbs.Crumb; + +/** + * @author Sergey.Malenkov + */ +final class PsiCrumb extends Crumb.Impl { + final PsiElement element; + CrumbPresentation presentation; + + PsiCrumb(PsiElement element, BreadcrumbsInfoProvider provider) { + super(null, provider.getElementInfo(element), provider.getElementTooltip(element)); + this.element = element; + } + + static PsiElement getElement(Crumb crumb) { + return crumb instanceof PsiCrumb ? ((PsiCrumb)crumb).element : null; + } + + static CrumbPresentation getPresentation(Crumb crumb) { + return crumb instanceof PsiCrumb ? ((PsiCrumb)crumb).presentation : null; + } +} From c0d4b2952508b669fabfa66dbe41f03a10012ca2 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Fri, 7 Apr 2017 22:18:13 +0300 Subject: [PATCH 111/111] IDEA-169924 / IDEA-157959 XML Breadcrumbs hold strong references to AST --- .../src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java b/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java index 6bb7a3150664..2a1729cd84e3 100644 --- a/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java +++ b/xml/impl/src/com/intellij/xml/breadcrumbs/BreadcrumbsXmlWrapper.java @@ -444,6 +444,7 @@ public class BreadcrumbsXmlWrapper extends JComponent implements Disposable { myEditor.putUserData(BREADCRUMBS_COMPONENT_KEY, null); } myEditor = null; + breadcrumbs.setCrumbs(null); } @Nullable