From d45c8a5da2bfc2ff4914b7254a897223402f4f87 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 17 Jun 2014 17:56:35 +0400 Subject: [PATCH 01/15] all inspections are suppressable by default; language suppressor is needed to provide non trivial implementation --- .../BaseJavaBatchLocalInspectionTool.java | 14 +------ .../BaseJavaLocalInspectionTool.java | 6 +-- .../GlobalJavaBatchInspectionTool.java | 12 +----- .../GlobalJavaInspectionTool.java | 8 ++-- .../UnusedSymbolLocalInspectionBase.java | 25 +----------- .../InspectionProfileEntry.java | 39 ++++++++++++++++++- .../codeInspection/LocalInspectionTool.java | 5 +++ .../daemon/impl/HighlightInfo.java | 28 +++++-------- .../codeInspection/SuppressionUtil.java | 20 +--------- .../ex/InspectionManagerEx.java | 17 ++++---- .../GroovySuppressableInspectionTool.java | 14 +------ .../rest/inspections/RestInspection.java | 11 +++--- .../inspections/PyDocstringInspection.java | 9 +++-- .../python/inspections/PyInspection.java | 18 ++++----- .../quickfix/PySuppressInspectionFix.java | 5 ++- .../inspections/SpellCheckingInspection.java | 11 ++---- .../XmlSuppressableInspectionTool.java | 13 +------ 17 files changed, 96 insertions(+), 159 deletions(-) diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/BaseJavaBatchLocalInspectionTool.java b/java/java-analysis-api/src/com/intellij/codeInspection/BaseJavaBatchLocalInspectionTool.java index 18f1c5128ab6..4b585c30cf83 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/BaseJavaBatchLocalInspectionTool.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/BaseJavaBatchLocalInspectionTool.java @@ -26,18 +26,8 @@ import org.jetbrains.annotations.Nullable; * - work with PSI or document only and * - don't provide {@link com.intellij.codeInsight.intention.IntentionAction} for quick fixes/suppression, making do with {@link LocalQuickFix} only. */ -public abstract class BaseJavaBatchLocalInspectionTool extends AbstractBaseJavaLocalInspectionTool implements BatchSuppressableTool { - @NotNull - @Override - public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) { - return BatchSuppressManager.SERVICE.getInstance().createBatchSuppressActions(HighlightDisplayKey.find(getShortName())); - } - - @Override - public boolean isSuppressedFor(@NotNull PsiElement element) { - return isSuppressedFor(element, this); - } - +public abstract class BaseJavaBatchLocalInspectionTool extends AbstractBaseJavaLocalInspectionTool { + @Deprecated public static boolean isSuppressedFor(@NotNull PsiElement element, @NotNull LocalInspectionTool tool) { BatchSuppressManager manager = BatchSuppressManager.SERVICE.getInstance(); String alternativeId; diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/BaseJavaLocalInspectionTool.java b/java/java-analysis-api/src/com/intellij/codeInspection/BaseJavaLocalInspectionTool.java index ab807d608579..df0085fff6de 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/BaseJavaLocalInspectionTool.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/BaseJavaLocalInspectionTool.java @@ -42,11 +42,7 @@ public abstract class BaseJavaLocalInspectionTool extends AbstractBaseJavaLocalI return SuppressManager.getInstance().createSuppressActions(key); } - @Override - public boolean isSuppressedFor(@NotNull PsiElement element) { - return isSuppressedFor(element, this); - } - + @Deprecated public static boolean isSuppressedFor(@NotNull PsiElement element, @NotNull LocalInspectionTool tool) { return BaseJavaBatchLocalInspectionTool.isSuppressedFor(element, tool); } diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/GlobalJavaBatchInspectionTool.java b/java/java-analysis-api/src/com/intellij/codeInspection/GlobalJavaBatchInspectionTool.java index 8c2726e77bef..5ac743d212ce 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/GlobalJavaBatchInspectionTool.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/GlobalJavaBatchInspectionTool.java @@ -26,7 +26,7 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public abstract class GlobalJavaBatchInspectionTool extends GlobalInspectionTool implements BatchSuppressableTool { +public abstract class GlobalJavaBatchInspectionTool extends GlobalInspectionTool { @Override public boolean queryExternalUsagesRequests(@NotNull final InspectionManager manager, @NotNull final GlobalInspectionContext globalContext, @@ -38,14 +38,4 @@ public abstract class GlobalJavaBatchInspectionTool extends GlobalInspectionTool return false; } - @NotNull - @Override - public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) { - return BatchSuppressManager.SERVICE.getInstance().createBatchSuppressActions(HighlightDisplayKey.find(getShortName())); - } - - @Override - public boolean isSuppressedFor(@NotNull final PsiElement element) { - return BatchSuppressManager.SERVICE.getInstance().isSuppressedFor(element, getShortName()); - } } diff --git a/java/java-analysis-api/src/com/intellij/codeInspection/GlobalJavaInspectionTool.java b/java/java-analysis-api/src/com/intellij/codeInspection/GlobalJavaInspectionTool.java index 1d9ff9c4a6cc..df596771a9c8 100644 --- a/java/java-analysis-api/src/com/intellij/codeInspection/GlobalJavaInspectionTool.java +++ b/java/java-analysis-api/src/com/intellij/codeInspection/GlobalJavaInspectionTool.java @@ -26,7 +26,7 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public abstract class GlobalJavaInspectionTool extends GlobalInspectionTool implements CustomSuppressableInspectionTool { +public abstract class GlobalJavaInspectionTool extends GlobalInspectionTool { @Override public boolean queryExternalUsagesRequests(@NotNull final InspectionManager manager, @NotNull final GlobalInspectionContext globalContext, @@ -38,10 +38,10 @@ public abstract class GlobalJavaInspectionTool extends GlobalInspectionTool impl return false; } + @NotNull @Override - @Nullable - public SuppressIntentionAction[] getSuppressActions(final PsiElement element) { - return SuppressManager.getInstance().createSuppressActions(HighlightDisplayKey.find(getShortName())); + public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) { + return BatchSuppressManager.SERVICE.getInstance().createBatchSuppressActions(HighlightDisplayKey.find(getShortName())); } @Override diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspectionBase.java index dc28a7b340c0..14da43194fe7 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/unusedSymbol/UnusedSymbolLocalInspectionBase.java @@ -15,14 +15,11 @@ */ package com.intellij.codeInspection.unusedSymbol; -import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; -import com.intellij.codeInspection.*; -import com.intellij.psi.PsiElement; +import com.intellij.codeInspection.BaseJavaLocalInspectionTool; import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -public class UnusedSymbolLocalInspectionBase extends AbstractBaseJavaLocalInspectionTool implements CustomSuppressableInspectionTool { +public class UnusedSymbolLocalInspectionBase extends BaseJavaLocalInspectionTool { @NonNls public static final String SHORT_NAME = HighlightInfoType.UNUSED_SYMBOL_SHORT_NAME; @NonNls public static final String DISPLAY_NAME = HighlightInfoType.UNUSED_SYMBOL_DISPLAY_NAME; @NonNls public static final String UNUSED_PARAMETERS_SHORT_NAME = "UnusedParameters"; @@ -33,22 +30,4 @@ public class UnusedSymbolLocalInspectionBase extends AbstractBaseJavaLocalInspec public boolean CLASS = true; public boolean PARAMETER = true; public boolean REPORT_PARAMETER_FOR_PUBLIC_METHODS = true; - - @Override - public boolean isSuppressedFor(@NotNull PsiElement element) { - return isSuppressedFor(element, this); - } - public static boolean isSuppressedFor(@NotNull PsiElement element, @NotNull LocalInspectionTool tool) { - return BaseJavaBatchLocalInspectionTool.isSuppressedFor(element, tool); - } - @Override - public SuppressIntentionAction[] getSuppressActions(final PsiElement element) { - String shortName = getShortName(); - HighlightDisplayKey key = HighlightDisplayKey.find(shortName); - if (key == null) { - throw new AssertionError("HighlightDisplayKey.find(" + shortName + ") is null. Inspection: "+getClass()); - } - SuppressQuickFix[] batchSuppressActions = BatchSuppressManager.SERVICE.getInstance().createBatchSuppressActions(key); - return SuppressIntentionActionFromFix.convertBatchToSuppressIntentionActions(batchSuppressActions); - } } diff --git a/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfileEntry.java b/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfileEntry.java index 0b8d36431d54..8b1bb2807750 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfileEntry.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/InspectionProfileEntry.java @@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiElement; import com.intellij.util.ResourceUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xmlb.SerializationFilter; @@ -46,7 +47,7 @@ import java.util.Set; * @since 28-Nov-2005 */ @SuppressWarnings("JavadocReference") -public abstract class InspectionProfileEntry { +public abstract class InspectionProfileEntry implements BatchSuppressableTool{ public static final String GENERAL_GROUP_NAME = InspectionsBundle.message("inspection.general.tools.group.name"); private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.InspectionProfileEntry"); @@ -56,6 +57,42 @@ public abstract class InspectionProfileEntry { private static final Object BLACK_LIST_LOCK = new Object(); private Boolean myUseNewSerializer = null; + @NonNls + @Nullable + public String getAlternativeID() { + return null; + } + + @Override + public boolean isSuppressedFor(@NotNull PsiElement element) { + InspectionSuppressor suppressor = LanguageInspectionSuppressors.INSTANCE.forLanguage(element.getLanguage()); + if (suppressor != null) { + String toolId = getSuppressId(); + if (suppressor.isSuppressedFor(element, toolId)) { + return true; + } + final String alternativeId = getAlternativeID(); + return alternativeId != null && !alternativeId.equals(toolId) && suppressor.isSuppressedFor(element, alternativeId); + } + return false; + } + + protected String getSuppressId() { + return getShortName(); + } + + @NotNull + @Override + public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) { + if (element != null) { + InspectionSuppressor suppressor = LanguageInspectionSuppressors.INSTANCE.forLanguage(element.getLanguage()); + if (suppressor != null) { + return suppressor.getSuppressActions(element, getShortName()); + } + } + return SuppressQuickFix.EMPTY_ARRAY; + } + public void cleanup(Project project) { } diff --git a/platform/analysis-api/src/com/intellij/codeInspection/LocalInspectionTool.java b/platform/analysis-api/src/com/intellij/codeInspection/LocalInspectionTool.java index db7d8c4bd806..b4cba852eba2 100644 --- a/platform/analysis-api/src/com/intellij/codeInspection/LocalInspectionTool.java +++ b/platform/analysis-api/src/com/intellij/codeInspection/LocalInspectionTool.java @@ -71,6 +71,11 @@ public abstract class LocalInspectionTool extends InspectionProfileEntry { return getShortName(); } + @Override + protected String getSuppressId() { + return getID(); + } + @NonNls @Nullable public String getAlternativeID() { diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfo.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfo.java index a8fe5d27dd16..483f3c5b2839 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfo.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/HighlightInfo.java @@ -830,33 +830,23 @@ public class HighlightInfo implements Segment { throw new AssertionError("unknown tool: " + toolWrapper+"; key: "+myKey); } - SuppressQuickFix[] suppressFixes = null; if (wrappedTool instanceof CustomSuppressableInspectionTool) { - suppressFixes = SuppressQuickFix.EMPTY_ARRAY; final IntentionAction[] suppressActions = ((CustomSuppressableInspectionTool)wrappedTool).getSuppressActions(element); if (suppressActions != null) { ContainerUtil.addAll(newOptions, suppressActions); } - } - if (wrappedTool instanceof BatchSuppressableTool) { - suppressFixes = ((BatchSuppressableTool)wrappedTool).getBatchSuppressActions(element); - } - - if (suppressFixes == null) { - final InspectionSuppressor suppressor = LanguageInspectionSuppressors.INSTANCE.forLanguage(element.getLanguage()); - if (suppressor != null) { - suppressFixes = suppressor.getSuppressActions(element, wrappedTool.getShortName()); + } else { + SuppressQuickFix[] suppressFixes = wrappedTool.getBatchSuppressActions(element); + if (suppressFixes.length > 0) { + ContainerUtil.addAll(newOptions, ContainerUtil.map(suppressFixes, new Function() { + @Override + public IntentionAction fun(SuppressQuickFix fix) { + return SuppressIntentionActionFromFix.convertBatchToSuppressIntentionAction(fix); + } + })); } } - if (suppressFixes != null) { - ContainerUtil.addAll(newOptions, ContainerUtil.map(suppressFixes, new Function() { - @Override - public IntentionAction fun(SuppressQuickFix fix) { - return SuppressIntentionActionFromFix.convertBatchToSuppressIntentionAction(fix); - } - })); - } } if (myProblemGroup instanceof SuppressableProblemGroup) { final IntentionAction[] suppressActions = ((SuppressableProblemGroup)myProblemGroup).getSuppressActions(element); diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/SuppressionUtil.java b/platform/analysis-impl/src/com/intellij/codeInspection/SuppressionUtil.java index 249696cd6c3f..4f1de6622a1f 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/SuppressionUtil.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/SuppressionUtil.java @@ -194,24 +194,6 @@ public class SuppressionUtil extends SuppressionUtilCore { } public static boolean inspectionResultSuppressed(@NotNull PsiElement place, @NotNull LocalInspectionTool tool) { - if (tool instanceof CustomSuppressableInspectionTool) { - return ((CustomSuppressableInspectionTool)tool).isSuppressedFor(place); - } - if (tool instanceof BatchSuppressableTool) { - return ((BatchSuppressableTool)tool).isSuppressedFor(place); - } - - final InspectionSuppressor suppressor = LanguageInspectionSuppressors.INSTANCE.forLanguage(place.getLanguage()); - if (suppressor != null) { - return suppressor.isSuppressedFor(place, tool.getID()); - } - - String alternativeId; - String id; - - return isSuppressed(place, id = tool.getID()) || - (alternativeId = tool.getAlternativeID()) != null && - !alternativeId.equals(id) && - isSuppressed(place, alternativeId); + return tool.isSuppressedFor(place); } } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionManagerEx.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionManagerEx.java index 17aaee57d8f5..2c934d76bbd5 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionManagerEx.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionManagerEx.java @@ -90,16 +90,13 @@ public class InspectionManagerEx extends InspectionManagerBase { if (tool instanceof CustomSuppressableInspectionTool) { return ((CustomSuppressableInspectionTool)tool).getSuppressActions(null); } - if (tool instanceof BatchSuppressableTool) { - LocalQuickFix[] actions = ((BatchSuppressableTool)tool).getBatchSuppressActions(null); - return ContainerUtil.map2Array(actions, SuppressIntentionAction.class, new Function() { - @Override - public SuppressIntentionAction fun(final LocalQuickFix fix) { - return SuppressIntentionActionFromFix.convertBatchToSuppressIntentionAction((SuppressQuickFix)fix); - } - }); - } - return null; + LocalQuickFix[] actions = tool.getBatchSuppressActions(null); + return ContainerUtil.map2Array(actions, SuppressIntentionAction.class, new Function() { + @Override + public SuppressIntentionAction fun(final LocalQuickFix fix) { + return SuppressIntentionActionFromFix.convertBatchToSuppressIntentionAction((SuppressQuickFix)fix); + } + }); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/GroovySuppressableInspectionTool.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/GroovySuppressableInspectionTool.java index 184476b33a7a..b348c9cabefd 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/GroovySuppressableInspectionTool.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/GroovySuppressableInspectionTool.java @@ -44,14 +44,7 @@ import java.util.regex.Matcher; /** * @author peter */ -public abstract class GroovySuppressableInspectionTool extends LocalInspectionTool implements BatchSuppressableTool { - @NotNull - @Override - public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) { - return getSuppressActions(getShortName()); - - } - +public abstract class GroovySuppressableInspectionTool extends LocalInspectionTool { public static SuppressQuickFix[] getSuppressActions(String name) { final HighlightDisplayKey displayKey = HighlightDisplayKey.find(name); return new SuppressQuickFix[] { @@ -61,11 +54,6 @@ public abstract class GroovySuppressableInspectionTool extends LocalInspectionTo }; } - @Override - public boolean isSuppressedFor(@NotNull final PsiElement element) { - return isElementToolSuppressedIn(element, getID()); - } - public static boolean isElementToolSuppressedIn(final PsiElement place, final String toolId) { return getElementToolSuppressedIn(place, toolId) != null; } diff --git a/python/python-rest/src/com/jetbrains/rest/inspections/RestInspection.java b/python/python-rest/src/com/jetbrains/rest/inspections/RestInspection.java index 0369198c3f3c..a22819d0cebd 100644 --- a/python/python-rest/src/com/jetbrains/rest/inspections/RestInspection.java +++ b/python/python-rest/src/com/jetbrains/rest/inspections/RestInspection.java @@ -15,9 +15,7 @@ */ package com.jetbrains.rest.inspections; -import com.intellij.codeInspection.CustomSuppressableInspectionTool; -import com.intellij.codeInspection.LocalInspectionTool; -import com.intellij.codeInspection.SuppressIntentionAction; +import com.intellij.codeInspection.*; import com.intellij.psi.PsiElement; import com.jetbrains.rest.RestBundle; import org.jetbrains.annotations.Nls; @@ -27,7 +25,7 @@ import org.jetbrains.annotations.Nullable; /** * User : catherine */ -public abstract class RestInspection extends LocalInspectionTool implements CustomSuppressableInspectionTool { +public abstract class RestInspection extends LocalInspectionTool { @Nls @NotNull @Override @@ -46,9 +44,10 @@ public abstract class RestInspection extends LocalInspectionTool implements Cust return true; } + @NotNull @Override - public SuppressIntentionAction[] getSuppressActions(@Nullable PsiElement element) { - return null; + public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) { + return SuppressQuickFix.EMPTY_ARRAY; } @Override diff --git a/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java b/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java index 5a7ac6ff9a30..ae47dbb6136e 100644 --- a/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyDocstringInspection.java @@ -21,7 +21,7 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.codeInspection.SuppressIntentionAction; +import com.intellij.codeInspection.SuppressQuickFix; import com.intellij.lang.ASTNode; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.TextRange; @@ -230,9 +230,10 @@ public class PyDocstringInspection extends PyInspection { } } + @NotNull @Override - public SuppressIntentionAction[] getSuppressActions(@Nullable PsiElement element) { - List result = new ArrayList(); + public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) { + List result = new ArrayList(); if (element != null) { if (PsiTreeUtil.getParentOfType(element, PyFunction.class) != null) { result.add(new PySuppressInspectionFix(getShortName().replace("Inspection", ""), "Suppress for function", PyFunction.class)); @@ -241,6 +242,6 @@ public class PyDocstringInspection extends PyInspection { result.add(new PySuppressInspectionFix(getShortName().replace("Inspection", ""), "Suppress for class", PyClass.class)); } } - return result.toArray(new SuppressIntentionAction[result.size()]); + return result.toArray(new SuppressQuickFix[result.size()]); } } diff --git a/python/src/com/jetbrains/python/inspections/PyInspection.java b/python/src/com/jetbrains/python/inspections/PyInspection.java index 9227f1c7d1d1..a35e2c774b05 100644 --- a/python/src/com/jetbrains/python/inspections/PyInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyInspection.java @@ -15,10 +15,7 @@ */ package com.jetbrains.python.inspections; -import com.intellij.codeInspection.CustomSuppressableInspectionTool; -import com.intellij.codeInspection.LocalInspectionTool; -import com.intellij.codeInspection.SuppressIntentionAction; -import com.intellij.codeInspection.SuppressionUtil; +import com.intellij.codeInspection.*; import com.intellij.psi.PsiComment; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -41,7 +38,7 @@ import java.util.regex.Pattern; /** * @author yole */ -public abstract class PyInspection extends LocalInspectionTool implements CustomSuppressableInspectionTool { +public abstract class PyInspection extends LocalInspectionTool { @Nls @NotNull @Override @@ -60,12 +57,13 @@ public abstract class PyInspection extends LocalInspectionTool implements Custom return true; } + @NotNull @Override - public SuppressIntentionAction[] getSuppressActions(@Nullable final PsiElement element) { - List result = new ArrayList(); + public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) { + List result = new ArrayList(); result.add(new PySuppressInspectionFix(getSuppressId(), "Suppress for statement", PyStatement.class) { @Override - protected PsiElement getContainer(PsiElement context) { + public PsiElement getContainer(PsiElement context) { if (PsiTreeUtil.getParentOfType(context, PyStatementList.class, false, ScopeOwner.class) != null || PsiTreeUtil.getParentOfType(context, PyFunction.class, PyClass.class) == null) { return super.getContainer(context); @@ -75,7 +73,7 @@ public abstract class PyInspection extends LocalInspectionTool implements Custom }); result.add(new PySuppressInspectionFix(getSuppressId(), "Suppress for function", PyFunction.class)); result.add(new PySuppressInspectionFix(getSuppressId(), "Suppress for class", PyClass.class)); - return result.toArray(new SuppressIntentionAction[result.size()]); + return result.toArray(new SuppressQuickFix[result.size()]); } @Override @@ -131,7 +129,7 @@ public abstract class PyInspection extends LocalInspectionTool implements Custom return m.matches() && SuppressionUtil.isInspectionToolIdMentioned(m.group(1), getSuppressId()); } - private String getSuppressId() { + protected String getSuppressId() { return getShortName().replace("Inspection", ""); } } diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PySuppressInspectionFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PySuppressInspectionFix.java index 9addabf06a98..0e6a7d98b356 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PySuppressInspectionFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PySuppressInspectionFix.java @@ -15,6 +15,7 @@ */ package com.jetbrains.python.inspections.quickfix; +import com.intellij.codeInsight.daemon.impl.actions.AbstractBatchSuppressByNoInspectionCommentFix; import com.intellij.codeInsight.daemon.impl.actions.AbstractSuppressByNoInspectionCommentFix; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; @@ -23,7 +24,7 @@ import com.jetbrains.python.psi.PyElement; /** * @author yole */ -public class PySuppressInspectionFix extends AbstractSuppressByNoInspectionCommentFix { +public class PySuppressInspectionFix extends AbstractBatchSuppressByNoInspectionCommentFix { private final Class myContainerClass; public PySuppressInspectionFix(final String ID, final String text, final Class containerClass) { @@ -33,7 +34,7 @@ public class PySuppressInspectionFix extends AbstractSuppressByNoInspectionComme } @Override - protected PsiElement getContainer(PsiElement context) { + public PsiElement getContainer(PsiElement context) { return PsiTreeUtil.getParentOfType(context, myContainerClass); } } diff --git a/spellchecker/src/com/intellij/spellchecker/inspections/SpellCheckingInspection.java b/spellchecker/src/com/intellij/spellchecker/inspections/SpellCheckingInspection.java index fefddce8dfb9..1f2244995f68 100644 --- a/spellchecker/src/com/intellij/spellchecker/inspections/SpellCheckingInspection.java +++ b/spellchecker/src/com/intellij/spellchecker/inspections/SpellCheckingInspection.java @@ -40,7 +40,7 @@ import java.awt.*; import java.util.Set; -public class SpellCheckingInspection extends LocalInspectionTool implements BatchSuppressableTool { +public class SpellCheckingInspection extends LocalInspectionTool { public static final String SPELL_CHECKING_INSPECTION_TOOL_NAME = "SpellCheckingInspection"; @Override @@ -66,12 +66,8 @@ public class SpellCheckingInspection extends LocalInspectionTool implements Batc if(strategy instanceof SuppressibleSpellcheckingStrategy) { return ((SuppressibleSpellcheckingStrategy)strategy).getSuppressActions(element, getShortName()); } - final InspectionSuppressor suppressor = LanguageInspectionSuppressors.INSTANCE.forLanguage(language); - if (suppressor != null) { - return suppressor.getSuppressActions(element, getShortName()); - } } - return SuppressQuickFix.EMPTY_ARRAY; + return super.getBatchSuppressActions(element); } private static SpellcheckingStrategy getSpellcheckingStrategy(@NotNull PsiElement element, @NotNull Language language) { @@ -90,8 +86,7 @@ public class SpellCheckingInspection extends LocalInspectionTool implements Batc if (strategy instanceof SuppressibleSpellcheckingStrategy) { return ((SuppressibleSpellcheckingStrategy)strategy).isSuppressedFor(element, getShortName()); } - final InspectionSuppressor suppressor = LanguageInspectionSuppressors.INSTANCE.forLanguage(language); - return suppressor != null && suppressor.isSuppressedFor(element, getShortName()); + return super.isSuppressedFor(element); } @Override diff --git a/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java b/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java index 9521814649e2..2a942b9f56af 100644 --- a/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java +++ b/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java @@ -26,25 +26,14 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool implements BatchSuppressableTool { +public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool { @NonNls static final String ALL = "ALL"; - @NotNull - @Override - public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) { - return getSuppressFixes(getID()); - } - public static SuppressQuickFix[] getSuppressFixes(final String shortName) { final String id = HighlightDisplayKey.find(shortName).getID(); return new SuppressQuickFix[]{new SuppressTagStatic(id), new SuppressForFile(id), new SuppressAllForFile()}; } - @Override - public boolean isSuppressedFor(@NotNull final PsiElement element) { - return XmlSuppressionProvider.isSuppressed(element, getID()); - } - public class SuppressTag extends SuppressTagStatic { public SuppressTag() { super(getID()); From bdb86cc8a4fadec7ea0a7bdf112247758383f787 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Tue, 17 Jun 2014 18:12:52 +0400 Subject: [PATCH 02/15] set displayed mnemonic index if there are several letters --- platform/platform-api/src/com/intellij/util/ui/FormBuilder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/platform-api/src/com/intellij/util/ui/FormBuilder.java b/platform/platform-api/src/com/intellij/util/ui/FormBuilder.java index aa48a37be5ee..c2d3d829440d 100644 --- a/platform/platform-api/src/com/intellij/util/ui/FormBuilder.java +++ b/platform/platform-api/src/com/intellij/util/ui/FormBuilder.java @@ -84,6 +84,7 @@ public class FormBuilder { final int index = UIUtil.getDisplayMnemonicIndex(labelText); if (index != -1) { label.setDisplayedMnemonic(labelText.charAt(index + 1)); + label.setDisplayedMnemonicIndex(index); } label.setLabelFor(component); From c78145020b944006e2bb744bfa24bdd7d4194770 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Tue, 17 Jun 2014 18:37:41 +0400 Subject: [PATCH 03/15] speed up variables tree update: if we use Application.invokeLater there are too many tree repaints --- .../intellij/xdebugger/impl/ui/tree/XDebuggerTree.java | 7 +++++++ .../impl/ui/tree/nodes/XDebuggerTreeNode.java | 4 ++++ .../impl/ui/tree/nodes/XValueContainerNode.java | 7 +++---- .../tree/nodes/XValueNodePresentationConfigurator.java | 10 ++++++++-- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTree.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTree.java index 3b3a481f9870..afb22607d5d6 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTree.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/XDebuggerTree.java @@ -27,6 +27,7 @@ import com.intellij.ui.PopupHandler; import com.intellij.ui.TreeSpeedSearch; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; +import com.intellij.util.containers.TransferToEDTQueue; import com.intellij.util.ui.TextTransferable; import com.intellij.xdebugger.XSourcePosition; import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider; @@ -56,6 +57,8 @@ import java.util.List; * @author nik */ public class XDebuggerTree extends DnDAwareTree implements DataProvider, Disposable { + private final TransferToEDTQueue myLaterInvocator = TransferToEDTQueue.createRunnableMerger("XDebuggerTree later invocator", 100); + private static final DataKey XDEBUGGER_TREE_KEY = DataKey.create("xdebugger.tree"); private static final Convertor SPEED_SEARCH_CONVERTER = new Convertor() { @Override @@ -324,4 +327,8 @@ public class XDebuggerTree extends DnDAwareTree implements DataProvider, Disposa public static XDebuggerTree getTree(DataContext context) { return XDEBUGGER_TREE_KEY.getData(context); } + + public TransferToEDTQueue getLaterInvocator() { + return myLaterInvocator; + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XDebuggerTreeNode.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XDebuggerTreeNode.java index dccd5fd4f3f2..e01d0ad7ce79 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XDebuggerTreeNode.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XDebuggerTreeNode.java @@ -189,4 +189,8 @@ public abstract class XDebuggerTreeNode implements TreeNode, TreeSpeedSearch.Pat component.append(link.getLinkText(), link.getTextAttributes(), link); } } + + void invokeNodeUpdate(Runnable runnable) { + myTree.getLaterInvocator().offer(runnable); + } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java index a7059a4a10e0..38d2547831fe 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java @@ -22,7 +22,6 @@ import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.SortedList; import com.intellij.xdebugger.frame.*; import com.intellij.xdebugger.impl.settings.XDebuggerSettingsManager; -import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import com.intellij.xdebugger.impl.ui.XDebuggerUIConstants; import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree; import org.jetbrains.annotations.NotNull; @@ -75,7 +74,7 @@ public abstract class XValueContainerNode Date: Tue, 17 Jun 2014 19:06:05 +0400 Subject: [PATCH 04/15] [JavaRearranger] arrangement parse info refactoring --- .../arrangement/FieldDependenciesManager.java | 56 +++++++++++++ .../arrangement/JavaArrangementParseInfo.java | 82 +++++-------------- 2 files changed, 76 insertions(+), 62 deletions(-) create mode 100644 java/java-impl/src/com/intellij/psi/codeStyle/arrangement/FieldDependenciesManager.java diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/FieldDependenciesManager.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/FieldDependenciesManager.java new file mode 100644 index 000000000000..cea1c9e07f4c --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/FieldDependenciesManager.java @@ -0,0 +1,56 @@ +/* + * 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.intellij.psi.codeStyle.arrangement; + +import com.intellij.psi.PsiField; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class FieldDependenciesManager { + private final Map> myFieldDependencies; + private final Map myFieldInfosMap = ContainerUtil.newHashMap(); + + public FieldDependenciesManager(@NotNull Map> fieldDependencies, @NotNull Map fields) { + myFieldDependencies = fieldDependencies; + for (PsiField field : fields.keySet()) { + JavaElementArrangementEntry entry = fields.get(field); + myFieldInfosMap.put(field, new ArrangementEntryDependencyInfo(entry)); + } + } + + @NotNull + public List getRoots() { + List list = ContainerUtil.newArrayList(); + + for (Map.Entry> entry : myFieldDependencies.entrySet()) { + ArrangementEntryDependencyInfo currentInfo = myFieldInfosMap.get(entry.getKey()); + + for (PsiField usedInInitialization : entry.getValue()) { + ArrangementEntryDependencyInfo fieldInfo = myFieldInfosMap.get(usedInInitialization); + if (fieldInfo != null) + currentInfo.addDependentEntryInfo(fieldInfo); + } + + list.add(currentInfo); + } + + return list; + } +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementParseInfo.java b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementParseInfo.java index 2796fecea024..9664bc223f8f 100644 --- a/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementParseInfo.java +++ b/java/java-impl/src/com/intellij/psi/codeStyle/arrangement/JavaArrangementParseInfo.java @@ -27,8 +27,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; -import java.util.HashMap; -import java.util.HashSet; /** * @author Denis Zhdanov @@ -36,28 +34,22 @@ import java.util.HashSet; */ public class JavaArrangementParseInfo { - @NotNull private final List myEntries = new ArrayList(); + private final List myEntries = new ArrayList(); - @NotNull private final Map, JavaArrangementPropertyInfo> myProperties - = new HashMap, JavaArrangementPropertyInfo>(); + private final Map, JavaArrangementPropertyInfo> myProperties = new HashMap, JavaArrangementPropertyInfo>(); - @NotNull private final List myMethodDependencyRoots - = new ArrayList(); + private final List myMethodDependencyRoots = new ArrayList(); + private final Map> myMethodDependencies = new HashMap>(); - @NotNull private final Map> myMethodDependencies - = new HashMap>(); + private final Map myMethodEntriesMap = new HashMap(); + private final Map>> myOverriddenMethods = new LinkedHashMap>>(); - @NotNull private final Map myMethodEntriesMap = - new HashMap(); - - @NotNull private final Map>> myOverriddenMethods - = new LinkedHashMap>>(); - - @NotNull private final Set myTmpMethodDependencyRoots = new LinkedHashSet(); - @NotNull private final Set myDependentMethods = new HashSet(); + private final Set myTmpMethodDependencyRoots = new LinkedHashSet(); + private final Set myDependentMethods = new HashSet(); private boolean myRebuildMethodDependencies; - @NotNull private FieldDependenciesManager myFieldDependenciesManager = new FieldDependenciesManager(); + private final HashMap myFields = ContainerUtil.newLinkedHashMap(); + private final Map> myFieldDependencies = ContainerUtil.newHashMap(); @NotNull public List getEntries() { @@ -96,8 +88,7 @@ public class JavaArrangementParseInfo { @Nullable private ArrangementEntryDependencyInfo buildMethodDependencyInfo(@NotNull final PsiMethod method, - @NotNull Map cache) - { + @NotNull Map cache) { JavaElementArrangementEntry entry = myMethodEntriesMap.get(method); if (entry == null) { return null; @@ -158,7 +149,7 @@ public class JavaArrangementParseInfo { } public void onFieldEntryCreated(@NotNull PsiField field, @NotNull JavaElementArrangementEntry entry) { - myFieldDependenciesManager.registerFieldAndEntry(field, entry); + myFields.put(field, entry); } public void onOverriddenMethod(@NotNull PsiMethod baseMethod, @NotNull PsiMethod overridingMethod) { @@ -201,7 +192,7 @@ public class JavaArrangementParseInfo { result.add(info); } } - + return result; } @@ -226,49 +217,16 @@ public class JavaArrangementParseInfo { } public void registerFieldInitializationDependency(@NotNull PsiField fieldToInitialize, @NotNull PsiField usedInInitialization) { - myFieldDependenciesManager.registerInitializationDependency(fieldToInitialize, usedInInitialization); + Set fields = myFieldDependencies.get(fieldToInitialize); + if (fields == null) { + fields = ContainerUtil.newHashSet(); + myFieldDependencies.put(fieldToInitialize, fields); + } + fields.add(usedInInitialization); } @NotNull public List getFieldDependencyRoots() { - return myFieldDependenciesManager.getRoots(); - } - - private static class FieldDependenciesManager { - private final Map> myFieldDependencies = ContainerUtil.newHashMap(); - private final Map myFieldInfosMap = ContainerUtil.newHashMap(); - - - public void registerFieldAndEntry(@NotNull PsiField field, @NotNull JavaElementArrangementEntry entry) { - myFieldInfosMap.put(field, new ArrangementEntryDependencyInfo(entry)); - } - - public void registerInitializationDependency(@NotNull PsiField fieldToInitialize, @NotNull PsiField usedInInitialization) { - Set fields = myFieldDependencies.get(fieldToInitialize); - if (fields == null) { - fields = new HashSet(); - myFieldDependencies.put(fieldToInitialize, fields); - } - fields.add(usedInInitialization); - } - - @NotNull - public List getRoots() { - List list = ContainerUtil.newArrayList(); - - for (Map.Entry> entry : myFieldDependencies.entrySet()) { - ArrangementEntryDependencyInfo currentInfo = myFieldInfosMap.get(entry.getKey()); - - for (PsiField usedInInitialization : entry.getValue()) { - ArrangementEntryDependencyInfo fieldInfo = myFieldInfosMap.get(usedInInitialization); - if (fieldInfo != null) - currentInfo.addDependentEntryInfo(fieldInfo); - } - - list.add(currentInfo); - } - - return list; - } + return new FieldDependenciesManager(myFieldDependencies, myFields).getRoots(); } } \ No newline at end of file From 7c0813c27a9e954203fb099139c1ae92d1f59860 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 17 Jun 2014 19:26:05 +0400 Subject: [PATCH 05/15] Add qualifier to unqualified method call quick fix added (similar to "Static Method Import...") IDEA-94719 --- .../intention/QuickFixFactory.java | 3 + .../impl/analysis/HighlightMethodUtil.java | 1 + .../intention/EmptyQuickFixFactory.java | 6 + .../impl/quickfix/AddMethodQualifierFix.java | 162 ++++++++++++++++++ .../impl/config/QuickFixFactoryImpl.java | 6 + .../addMethodCallQualifier/Constructor.java | 26 +++ .../addMethodCallQualifier/FixAfter.java | 20 +++ .../addMethodCallQualifier/FixBefore.java | 20 +++ .../addMethodCallQualifier/NestedMethod.java | 36 ++++ .../NonStaticMethod.java | 26 +++ .../StaticInitializer.java | 26 +++ .../addMethodCallQualifier/StaticMethod.java | 26 +++ .../quickFix/AddMethodQualifierTest.java | 104 +++++++++++ .../src/messages/QuickFixBundle.properties | 4 +- 14 files changed, 465 insertions(+), 1 deletion(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddMethodQualifierFix.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/Constructor.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/FixAfter.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/FixBefore.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/NestedMethod.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/NonStaticMethod.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/StaticInitializer.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/StaticMethod.java create mode 100644 java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AddMethodQualifierTest.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 1a54284d17a3..5e1cb191ecdd 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 @@ -262,4 +262,7 @@ public abstract class QuickFixFactory { @NotNull Collection missedElements); @NotNull public abstract IntentionAction createSurroundWithQuotesAnnotationParameterValueFix(@NotNull PsiAnnotationMemberValue value, @NotNull PsiType expectedType); + + @NotNull + public abstract IntentionAction addMethodQualifierFix(@NotNull PsiMethodCallExpression methodCall); } 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 692783466b14..b567ce41325a 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 @@ -670,6 +670,7 @@ public class HighlightMethodUtil { registerChangeParameterClassFix(methodCall, list, highlightInfo); if (methodCandidates.length == 0) { QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.createStaticImportMethodFix(methodCall)); + QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, QUICK_FIX_FACTORY.addMethodQualifierFix(methodCall)); } for (IntentionAction action : QUICK_FIX_FACTORY.getVariableTypeFromCallFixes(methodCall, list)) { QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, action); 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 a69603bdcecd..e886be781eab 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 @@ -602,4 +602,10 @@ public class EmptyQuickFixFactory extends QuickFixFactory { @NotNull PsiType expectedType) { return QuickFixes.EMPTY_FIX; } + + @NotNull + @Override + public IntentionAction addMethodQualifierFix(@NotNull PsiMethodCallExpression methodCall) { + return QuickFixes.EMPTY_FIX; + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddMethodQualifierFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddMethodQualifierFix.java new file mode 100644 index 000000000000..ff851372e208 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddMethodQualifierFix.java @@ -0,0 +1,162 @@ +/* + * 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.intellij.codeInsight.daemon.impl.quickfix; + +import com.intellij.codeInsight.daemon.QuickFixBundle; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.PopupStep; +import com.intellij.openapi.ui.popup.util.BaseListPopupStep; +import com.intellij.psi.*; +import com.intellij.ui.popup.list.ListPopupImpl; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ObjectUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Dmitry Batkovich + */ +public class AddMethodQualifierFix implements IntentionAction { + private static final boolean UNIT_TEST_MODE = ApplicationManager.getApplication().isUnitTestMode(); + + private final SmartPsiElementPointer myMethodCall; + private List myCandidates = null; + + public AddMethodQualifierFix(final PsiMethodCallExpression methodCallExpression) { + myMethodCall = SmartPointerManager.getInstance(methodCallExpression.getProject()).createSmartPsiElementPointer(methodCallExpression); + } + + @NotNull + @Override + public String getText() { + String text = QuickFixBundle.message("add.method.qualifier.fix.text", myCandidates.size() > 1 ? "" : myCandidates.get(0).getName()); + if (myCandidates.size() > 1) { + text += "..."; + } + return text; + } + + @NotNull + @Override + public String getFamilyName() { + return getText(); + } + + @Override + public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) { + final PsiMethodCallExpression element = myMethodCall.getElement(); + if (element == null || !element.isValid()) { + return false; + } + if (myCandidates == null) { + findCandidates(); + } + return myCandidates.size() != 0; + } + + private void findCandidates() { + myCandidates = new ArrayList(); + final PsiMethodCallExpression methodCallElement = myMethodCall.getElement(); + final String methodName = methodCallElement.getMethodExpression().getReferenceName(); + if (methodName == null) { + return; + } + + for (final PsiVariable var : CreateFromUsageUtils.guessMatchingVariables(methodCallElement)) { + final PsiType type = var.getType(); + if (!(type instanceof PsiClassType)) { + continue; + } + final PsiClass resolvedClass = ((PsiClassType)type).resolve(); + if (resolvedClass == null) { + continue; + } + if (resolvedClass.findMethodsByName(methodName, true).length > 0) { + myCandidates.add(var); + } + } + } + + @TestOnly + public List getCandidates() { + return myCandidates; + } + + @Override + public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { + if (myCandidates.size() == 1 || UNIT_TEST_MODE) { + qualify(myCandidates.get(0), editor); + } + else { + chooseAndQualify(editor); + } + } + + private void chooseAndQualify(final Editor editor) { + final BaseListPopupStep step = + new BaseListPopupStep(QuickFixBundle.message("add.qualifier"), myCandidates) { + @Override + public PopupStep onChosen(final PsiVariable selectedValue, final boolean finalChoice) { + if (selectedValue != null && finalChoice) { + WriteCommandAction.runWriteCommandAction(selectedValue.getProject(), new Runnable() { + @Override + public void run() { + qualify(selectedValue, editor); + } + }); + } + return FINAL_CHOICE; + } + + @NotNull + @Override + public String getTextFor(final PsiVariable value) { + return ObjectUtils.assertNotNull(value.getName()); + } + + @Override + public Icon getIconFor(final PsiVariable aValue) { + return aValue.getIcon(0); + } + }; + + final ListPopupImpl popup = new ListPopupImpl(step); + popup.showInBestPositionFor(editor); + } + + private void qualify(final PsiVariable qualifier, final Editor editor) { + final String qualifierPresentableText = qualifier.getName(); + final PsiMethodCallExpression oldExpression = myMethodCall.getElement(); + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(qualifier.getProject()); + final PsiExpression expression = elementFactory + .createExpressionFromText(qualifierPresentableText + "." + oldExpression.getMethodExpression().getReferenceName() + "()", null); + final PsiElement replacedExpression = oldExpression.replace(expression); + editor.getCaretModel().moveToOffset(replacedExpression.getTextOffset() + replacedExpression.getTextLength()); + } + + @Override + public boolean startInWriteAction() { + return true; + } +} \ No newline at end of file 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 e934a9f387cf..81f0204049b6 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 @@ -762,6 +762,12 @@ public class QuickFixFactoryImpl extends QuickFixFactory { return new SurroundWithQuotesAnnotationParameterValueFix(value, expectedType); } + @NotNull + @Override + public IntentionAction addMethodQualifierFix(@NotNull PsiMethodCallExpression methodCall) { + return new AddMethodQualifierFix(methodCall); + } + private static boolean timeToOptimizeImports(@NotNull PsiFile file) { if (!CodeInsightSettings.getInstance().OPTIMIZE_IMPORTS_ON_THE_FLY) return false; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/Constructor.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/Constructor.java new file mode 100644 index 000000000000..fa782b8f177d --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/Constructor.java @@ -0,0 +1,26 @@ +public class A { + + Project p; + MyElement fieldElement; + + static MyElement staticElement; + + public A() { + + MyElement localElement1 = getElement(); + + getProject(); + + MyElement localElement2 = getElement(); + + } + + interface Project { + + } + + interface MyElement { + Project getProject(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/FixAfter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/FixAfter.java new file mode 100644 index 000000000000..171715cd7572 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/FixAfter.java @@ -0,0 +1,20 @@ +public class A { + + Project p; + MyElement fieldElement; + + static MyElement staticElement; + + public void m() { + fieldElement.getProject(); + } + + interface Project { + + } + + interface MyElement { + Project getProject(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/FixBefore.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/FixBefore.java new file mode 100644 index 000000000000..9996e8aea88e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/FixBefore.java @@ -0,0 +1,20 @@ +public class A { + + Project p; + MyElement fieldElement; + + static MyElement staticElement; + + public void m() { + getProject(); + } + + interface Project { + + } + + interface MyElement { + Project getProject(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/NestedMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/NestedMethod.java new file mode 100644 index 000000000000..1135da99aa74 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/NestedMethod.java @@ -0,0 +1,36 @@ +import java.lang.Object; + +public class A { + + Project p; + MyElement fieldElement; + + static MyElement staticElement; + + public void m(MyElement paramElement) { + + Object o = new Object() { + + private final MyElement nestedField; + + public void targetMethod(MyElement nestedParamElement) { + + final MyElement localElement1 = getElement(); + + getProject (); + + MyElement localElement2 = getElement(); + + } + } + } + + interface Project { + + } + + interface MyElement { + Project getProject(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/NonStaticMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/NonStaticMethod.java new file mode 100644 index 000000000000..6407fa18e304 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/NonStaticMethod.java @@ -0,0 +1,26 @@ +public class A { + + Project p; + MyElement fieldElement; + + static MyElement staticElement; + + public void targetMethod(MyElement paramElement) { + + MyElement localElement1 = getElement(); + + getProject(); + + MyElement localElement2 = getElement(); + + } + + interface Project { + + } + + interface MyElement { + Project getProject(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/StaticInitializer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/StaticInitializer.java new file mode 100644 index 000000000000..94faa3139b6c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/StaticInitializer.java @@ -0,0 +1,26 @@ +public class A { + + Project p; + MyElement fieldElement; + + static MyElement staticElement; + + static { + + MyElement localElement1 = getElement(); + + getProject(); + + MyElement localElement2 = getElement(); + + } + + interface Project { + + } + + interface MyElement { + Project getProject(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/StaticMethod.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/StaticMethod.java new file mode 100644 index 000000000000..b7f033a546d4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/StaticMethod.java @@ -0,0 +1,26 @@ +public class A { + + Project p; + MyElement fieldElement; + + static MyElement staticElement; + + public static void targetMethod(MyElement paramElement) { + + MyElement localElement1 = getElement(); + + getProject(); + + MyElement localElement2 = getElement(); + + } + + interface Project { + + } + + interface MyElement { + Project getProject(); + } + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AddMethodQualifierTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AddMethodQualifierTest.java new file mode 100644 index 000000000000..48572b2c8068 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/AddMethodQualifierTest.java @@ -0,0 +1,104 @@ +/* + * 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.intellij.codeInsight.daemon.quickFix; + +import com.intellij.JavaTestUtil; +import com.intellij.codeInsight.daemon.impl.quickfix.AddMethodQualifierFix; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.psi.PsiNamedElement; +import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * @author Dmitry Batkovich + */ +public class AddMethodQualifierTest extends JavaCodeInsightFixtureTestCase { + + @Override + protected String getTestDataPath() { + return JavaTestUtil.getJavaTestDataPath() + "/codeInsight/daemonCodeAnalyzer/quickFix/addMethodCallQualifier/"; + } + + public void testNonStaticMethod() { + doTest("fieldElement", "staticElement", "localElement1", "paramElement"); + } + + public void testStaticMethod() { + doTest("staticElement", "localElement1", "paramElement"); + } + + public void testNestedMethod() { + doTest("fieldElement", "localElement1", "nestedField", "nestedParamElement", "staticElement", "paramElement"); + } + + public void testConstructor() { + doTest("fieldElement", "staticElement", "localElement1"); + } + + public void testStaticInitializer() { + doTest("staticElement", "localElement1"); + } + + public void testFix() { + doTestFix(); + } + + private void doTestFix() { + myFixture.configureByFile(getTestName(false) + "Before.java"); + final AddMethodQualifierFix quickFix = getQuickFix(); + assertNotNull(quickFix); + myFixture.launchAction(quickFix); + myFixture.checkResultByFile(getTestName(false) + "After.java"); + } + + private void doTest(final String... candidatesNames) { + myFixture.configureByFile(getTestName(false) + ".java"); + final AddMethodQualifierFix addMethodQualifierFix = getQuickFix(); + if (candidatesNames.length == 0) { + assertNull(addMethodQualifierFix); + return; + } + assertNotNull(addMethodQualifierFix); + final Set actualCandidatesNames = new TreeSet(ContainerUtil.map(addMethodQualifierFix.getCandidates(), new Function() { + @Override + public String fun(final PsiNamedElement psiNamedElement) { + final String name = psiNamedElement.getName(); + assertNotNull(name); + return name; + } + })); + final Set expectedCandidatesNames = new TreeSet(ContainerUtil.list(candidatesNames)); + assertEquals(expectedCandidatesNames, actualCandidatesNames); + } + + @Nullable + private AddMethodQualifierFix getQuickFix() { + final List availableIntentions = myFixture.getAvailableIntentions(); + AddMethodQualifierFix addMethodQualifierFix = null; + for (final IntentionAction availableIntention : availableIntentions) { + if (availableIntention instanceof AddMethodQualifierFix) { + addMethodQualifierFix = (AddMethodQualifierFix)availableIntention; + break; + } + } + return addMethodQualifierFix; + } + +} diff --git a/resources-en/src/messages/QuickFixBundle.properties b/resources-en/src/messages/QuickFixBundle.properties index 9e94379d7892..08cd32e9972b 100644 --- a/resources-en/src/messages/QuickFixBundle.properties +++ b/resources-en/src/messages/QuickFixBundle.properties @@ -281,4 +281,6 @@ wrap.array.to.arrays.as.list.single.parameter.text=Wrap using ''Arrays.asList'' annotations.fix=Annotations add.missing.annotation.parameters.fix=Add missing annotation parameters - {0} -add.missing.annotation.single.parameter.fix=Add missing annotation parameter ''{0}'' \ No newline at end of file +add.missing.annotation.single.parameter.fix=Add missing annotation parameter ''{0}'' + +add.method.qualifier.fix.text=Add Qualifier {0} to Method \ No newline at end of file From 8e3d3f5a8c4889087cbe8eb328dcc58145a92f93 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 17 Jun 2014 13:28:58 +0200 Subject: [PATCH 06/15] IDEA-126211 The Power Save mode action should explain what it does --- .../ide/actions/PowerSaveModeNotifier.java | 67 +++++++++++++++++++ .../ide/actions/TogglePowerSaveAction.java | 4 ++ .../com/intellij/ide/SystemHealthMonitor.java | 22 ------ .../src/META-INF/PlatformExtensions.xml | 1 + 4 files changed, 72 insertions(+), 22 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/ide/actions/PowerSaveModeNotifier.java diff --git a/platform/lang-impl/src/com/intellij/ide/actions/PowerSaveModeNotifier.java b/platform/lang-impl/src/com/intellij/ide/actions/PowerSaveModeNotifier.java new file mode 100644 index 000000000000..91805bf32123 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/ide/actions/PowerSaveModeNotifier.java @@ -0,0 +1,67 @@ +/* + * 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.intellij.ide.actions; + +import com.intellij.ide.PowerSaveMode; +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationListener; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.startup.StartupActivity; +import org.jetbrains.annotations.NotNull; + +import javax.swing.event.HyperlinkEvent; + +/** + * @author peter + */ +public class PowerSaveModeNotifier implements StartupActivity { + private static final NotificationGroup POWER_SAVE_MODE = NotificationGroup.balloonGroup("Power Save Mode"); + private static final String IGNORE_POWER_SAVE_MODE = "ignore.power.save.mode"; + + @Override + public void runActivity(@NotNull Project project) { + if (PowerSaveMode.isEnabled()) { + notifyOnPowerSaveMode(project); + } + } + + static void notifyOnPowerSaveMode(Project project) { + if (PropertiesComponent.getInstance().getBoolean(IGNORE_POWER_SAVE_MODE, false)) { + return; + } + + String message = "Code insight and other background tasks are disabled." + + "
Do not show again" + + "
Disable Power Save Mode"; + POWER_SAVE_MODE.createNotification("Power save mode is on", message, NotificationType.WARNING, new NotificationListener() { + @Override + public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { + final String description = event.getDescription(); + if ("ignore".equals(description)) { + PropertiesComponent.getInstance().setValue(IGNORE_POWER_SAVE_MODE, "true"); + notification.expire(); + } + else if ("turnOff".equals(description)) { + PowerSaveMode.setEnabled(false); + notification.expire(); + } + } + }).notify(project); + } +} diff --git a/platform/lang-impl/src/com/intellij/ide/actions/TogglePowerSaveAction.java b/platform/lang-impl/src/com/intellij/ide/actions/TogglePowerSaveAction.java index 3040982f253b..40028e0eb3e0 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/TogglePowerSaveAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/TogglePowerSaveAction.java @@ -17,6 +17,7 @@ package com.intellij.ide.actions; import com.intellij.ide.PowerSaveMode; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.ToggleAction; import com.intellij.openapi.project.DumbAware; @@ -32,5 +33,8 @@ public class TogglePowerSaveAction extends ToggleAction implements DumbAware { @Override public void setSelected(AnActionEvent e, boolean state) { PowerSaveMode.setEnabled(state); + if (state) { + PowerSaveModeNotifier.notifyOnPowerSaveMode(e.getData(CommonDataKeys.PROJECT)); + } } } diff --git a/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java b/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java index f8c4e3cae144..e49cef42cc81 100644 --- a/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java +++ b/platform/platform-impl/src/com/intellij/ide/SystemHealthMonitor.java @@ -62,7 +62,6 @@ public class SystemHealthMonitor extends ApplicationComponent.Adapter { public void initComponent() { checkJvm(); startDiskSpaceMonitoring(); - checkPowerSaveMode(); } private void checkJvm() { @@ -210,25 +209,4 @@ public class SystemHealthMonitor extends ApplicationComponent.Adapter { }, 1, TimeUnit.SECONDS); } - private void checkPowerSaveMode() { - if (PowerSaveMode.isEnabled()) { - final String ignoreKey = "ignore.power.save.mode"; - String message = "Power save mode is on. Code insight and other background tasks are disabled." + - "
Do not show again" + - "
Disable Power Save Mode"; - - showNotification(ignoreKey, message, new HyperlinkAdapter() { - @Override - protected void hyperlinkActivated(HyperlinkEvent e) { - final String description = e.getDescription(); - if ("ignore".equals(description)) { - myProperties.setValue(ignoreKey, "true"); - } - else if ("turnOff".equals(description)) { - PowerSaveMode.setEnabled(false); - } - } - }); - } - } } diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 8b17da2d6dd5..126053b9d3b7 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -283,6 +283,7 @@ serviceImplementation="com.intellij.ide.TypePresentationServiceImpl"/> + From 5d5dda3057641d7db91a43eeaa797c6a3209aeb9 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 17 Jun 2014 15:42:06 +0200 Subject: [PATCH 07/15] explicitly ensure PushedFilePropertiesUpdater walks the whole project before UnindexedFilesUpdater --- .../impl/PushedFilePropertiesUpdater.java | 28 ++++++++++--------- .../util/indexing/UnindexedFilesUpdater.java | 2 +- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java index 4ec190127427..1247b582b10e 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdater.java @@ -59,7 +59,7 @@ public class PushedFilePropertiesUpdater { private final Project myProject; private final FilePropertyPusher[] myPushers; private final FilePropertyPusher[] myFilePushers; - private final Queue myTasks = new ConcurrentLinkedQueue(); + private final Queue myTasks = new ConcurrentLinkedQueue(); private final MessageBusConnection myConnection; public static PushedFilePropertiesUpdater getInstance(Project project) { @@ -84,7 +84,6 @@ public class PushedFilePropertiesUpdater { myConnection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() { @Override public void rootsChanged(final ModuleRootEvent event) { - pushAll(myPushers); for (FilePropertyPusher pusher : myPushers) { pusher.afterRootsChanged(project); } @@ -123,8 +122,6 @@ public class PushedFilePropertiesUpdater { } public void initializeProperties() { - pushAll(myPushers); - for (final FilePropertyPusher pusher : myPushers) { pusher.initExtra(myProject, myProject.getMessageBus(), new FilePropertyPusher.Engine() { @Override @@ -140,13 +137,18 @@ public class PushedFilePropertiesUpdater { } } + public void pushAllPropertiesNow() { + performPushTasks(); + doPushAll(myPushers); + } + private void schedulePushRecursively(final VirtualFile dir, final FilePropertyPusher... pushers) { if (pushers.length == 0) return; final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); if (!fileIndex.isInContent(dir)) return; - queueTask(new DumbModeTask() { + queueTask(new Runnable() { @Override - public void performInDumbMode(@NotNull final ProgressIndicator indicator) { + public void run() { doPushRecursively(dir, pushers, fileIndex); } }); @@ -162,25 +164,25 @@ public class PushedFilePropertiesUpdater { }); } - private void queueTask(DumbModeTask task) { + private void queueTask(Runnable task) { myTasks.offer(task); DumbService.getInstance(myProject).queueTask(new DumbModeTask() { @Override public void performInDumbMode(@NotNull ProgressIndicator indicator) { - performPushTasks(indicator); + performPushTasks(); } }); } - public void performPushTasks(ProgressIndicator indicator) { + private void performPushTasks() { boolean hadTasks = false; while (true) { - DumbModeTask task = myTasks.poll(); + Runnable task = myTasks.poll(); if (task == null) { break; } hadTasks = true; - task.performInDumbMode(indicator); + task.run(); } if (hadTasks && !myProject.isDisposed()) { @@ -213,9 +215,9 @@ public class PushedFilePropertiesUpdater { } public void pushAll(final FilePropertyPusher... pushers) { - queueTask(new DumbModeTask() { + queueTask(new Runnable() { @Override - public void performInDumbMode(@NotNull ProgressIndicator indicator) { + public void run() { doPushAll(pushers); } }); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java index c044a8ea9a00..8647b951407e 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UnindexedFilesUpdater.java @@ -51,7 +51,7 @@ public class UnindexedFilesUpdater extends DumbModeTask { } private void updateUnindexedFiles(ProgressIndicator indicator) { - PushedFilePropertiesUpdater.getInstance(myProject).performPushTasks(indicator); + PushedFilePropertiesUpdater.getInstance(myProject).pushAllPropertiesNow(); indicator.setIndeterminate(true); indicator.setText(IdeBundle.message("progress.indexing.scanning")); From baf01f80eb53b47d95ec247a1c8f1e094128739d Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 17 Jun 2014 15:55:22 +0200 Subject: [PATCH 08/15] wrap CacheUpdater into DumbServiceTask and not vice versa; simplify dumb tasks execution --- .../openapi/project/CacheUpdateRunner.java | 28 +- .../openapi/project/DumbServiceImpl.java | 346 ++++++------------ 2 files changed, 132 insertions(+), 242 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/project/CacheUpdateRunner.java b/platform/platform-impl/src/com/intellij/openapi/project/CacheUpdateRunner.java index 7cb5873e3f9f..9d6aa539a277 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/CacheUpdateRunner.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/CacheUpdateRunner.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.project; +import com.intellij.ide.IdeBundle; import com.intellij.ide.caches.CacheUpdater; import com.intellij.ide.caches.FileContent; import com.intellij.openapi.application.Application; @@ -40,7 +41,7 @@ import java.util.Set; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; -public class CacheUpdateRunner { +public class CacheUpdateRunner extends DumbModeTask { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.project.CacheUpdateRunner"); private static final Key FAILED_TO_INDEX = Key.create("FAILED_TO_INDEX"); private static final int PROC_COUNT = Runtime.getRuntime().availableProcessors(); @@ -58,15 +59,11 @@ public class CacheUpdateRunner { return new ArrayList(myUpdaters).toString(); } - public int queryNeededFiles(@NotNull ProgressIndicator indicator) { + private int queryNeededFiles(@NotNull ProgressIndicator indicator) { // can be queried twice in DumbService return getSession(indicator).getFilesToUpdate().size(); } - public int getNumberOfPendingUpdateJobs(@NotNull ProgressIndicator indicator) { - return getSession(indicator).getNumberOfPendingUpdateJobs(); - } - @NotNull private CacheUpdateSession getSession(@NotNull ProgressIndicator indicator) { CacheUpdateSession session = mySession; @@ -76,7 +73,7 @@ public class CacheUpdateRunner { return session; } - public void processFiles(@NotNull final ProgressIndicator indicator, boolean processInReadAction) { + private void processFiles(@NotNull final ProgressIndicator indicator, boolean processInReadAction) { try { Collection files = mySession.getFilesToUpdate(); @@ -134,7 +131,7 @@ public class CacheUpdateRunner { } } - public void updatingDone() { + private void updatingDone() { try { mySession.updatingDone(); } @@ -217,6 +214,21 @@ public class CacheUpdateRunner { return false; } + @Override + public void performInDumbMode(@NotNull ProgressIndicator indicator) { + indicator.checkCanceled(); + indicator.setIndeterminate(true); + indicator.setText(IdeBundle.message("progress.indexing.scanning")); + int count = queryNeededFiles(indicator); + + indicator.setIndeterminate(false); + indicator.setText(IdeBundle.message("progress.indexing.updating")); + if (count > 0) { + processFiles(indicator, true); + } + updatingDone(); + } + private static class MyRunnable implements Runnable { private final ProgressIndicatorBase myInnerIndicator; private final FileContentQueue myQueue; diff --git a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java index f71eb5fef698..bfdb8a6e4b6b 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java @@ -17,7 +17,6 @@ package com.intellij.openapi.project; import com.intellij.ide.IdeBundle; import com.intellij.ide.caches.CacheUpdater; -import com.intellij.ide.caches.FileContent; import com.intellij.ide.util.DelegatingProgressIndicator; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.Application; @@ -29,8 +28,8 @@ import com.intellij.openapi.progress.*; import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.ShutDownTracker; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.AppIconScheme; import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.WindowManager; @@ -48,21 +47,15 @@ import org.jetbrains.annotations.TestOnly; import javax.swing.*; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; public class DumbServiceImpl extends DumbService { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.project.DumbServiceImpl"); private volatile boolean myDumb = false; private final DumbModeListener myPublisher; - private final Queue myUpdatesQueue = new Queue(5); + private final Queue myUpdatesQueue = new Queue(5); private final Queue myRunWhenSmartQueue = new Queue(5); private final Project myProject; - private final CacheUpdateRunner NULL_ACTION; @SuppressWarnings({"MethodOverridesStaticMethodOfSuperclass"}) public static DumbServiceImpl getInstance(@NotNull Project project) { @@ -71,45 +64,12 @@ public class DumbServiceImpl extends DumbService { @Override public void queueTask(final DumbModeTask task) { - CacheUpdater wrapper = new CacheUpdater() { - @Override - public int getNumberOfPendingUpdateJobs() { - return 0; - } - - @NotNull - @Override - public VirtualFile[] queryNeededFiles(@NotNull ProgressIndicator indicator) { - task.performInDumbMode(indicator); - return new VirtualFile[0]; - } - - @Override - public void processFile(@NotNull FileContent fileContent) { - - } - - @Override - public void updatingDone() { - } - - @Override - public void canceled() { - - } - - @Override - public String toString() { - return task.toString(); - } - }; - queueCacheUpdateInDumbMode(Arrays.asList(wrapper)); + scheduleCacheUpdate(task, true); } public DumbServiceImpl(Project project, MessageBus bus) { myProject = project; myPublisher = bus.syncPublisher(DUMB_MODE); - NULL_ACTION = new CacheUpdateRunner(project, Collections.emptyList()); } @Override @@ -145,87 +105,45 @@ public class DumbServiceImpl extends DumbService { } } + @SuppressWarnings("deprecation") public void queueCacheUpdate(@NotNull Collection updaters) { - scheduleCacheUpdate(updaters, false); + scheduleCacheUpdate(new CacheUpdateRunner(myProject, new ArrayList(updaters)), false); } + @SuppressWarnings("deprecation") public void queueCacheUpdateInDumbMode(@NotNull Collection updaters) { - scheduleCacheUpdate(updaters, true); + scheduleCacheUpdate(new CacheUpdateRunner(myProject, new ArrayList(updaters)), true); } - private void scheduleCacheUpdate(@NotNull Collection updaters, boolean forceDumbMode) { - // prevent concurrent modifications - final CacheUpdateRunner runner = new CacheUpdateRunner(myProject, new ArrayList(updaters)); - + private void scheduleCacheUpdate(@NotNull final DumbModeTask task, boolean forceDumbMode) { final Application application = ApplicationManager.getApplication(); - if (application.isUnitTestMode() || application.isHeadlessEnvironment()) { - // no dumb mode for tests - EmptyProgressIndicator i = new EmptyProgressIndicator(); - final int size = runner.queryNeededFiles(i); + if (application.isUnitTestMode() || application.isHeadlessEnvironment() || !forceDumbMode && !myDumb && application.isReadAccessAllowed()) { + final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); + if (indicator != null) { + indicator.pushState(); + } try { HeavyProcessLatch.INSTANCE.processStarted(); - if (size > 0) { - runner.processFiles(i, false); - } - runner.updatingDone(); + task.performInDumbMode(indicator != null ? indicator : new EmptyProgressIndicator()); } finally { HeavyProcessLatch.INSTANCE.processFinished(); - } - return; - } - - if (!forceDumbMode && !myDumb && application.isReadAccessAllowed()) { - // if there are not so many files to process, process them on the spot without entering dumb mode - final ProgressIndicator currentIndicator = ProgressManager.getInstance().getProgressIndicator(); - final ProgressIndicator indicator; - if (currentIndicator != null) { - indicator = currentIndicator; - currentIndicator.pushState(); - } - else { - indicator = new EmptyProgressIndicator(); - } - try { - final int size = runner.queryNeededFiles(indicator); - if (size + runner.getNumberOfPendingUpdateJobs(indicator) < 50) { - // If not that many files found, process them on the spot, avoiding entering dumb mode - // Consider number of pending tasks as well, because they may take noticeable time to process even if the number of files is small - try { - HeavyProcessLatch.INSTANCE.processStarted(); - if (size > 0) { - runner.processFiles(indicator, false); - } - runner.updatingDone(); - } - finally { - HeavyProcessLatch.INSTANCE.processFinished(); - } - return; - } - } - finally { - if (currentIndicator != null) { - currentIndicator.popState(); + if (indicator != null) { + indicator.popState(); } } } - - final IndexUpdateRunnable updateRunnable = new IndexUpdateRunnable(runner); - UIUtil.invokeLaterIfNeeded(new DumbAwareRunnable() { @Override public void run() { if (myProject.isDisposed()) { return; } + myUpdatesQueue.addLast(task); // ok to test and set the flag like this, because the change is always done from dispatch thread - if (myDumb) { - myUpdatesQueue.addLast(updateRunnable); - } - else { + if (!myDumb) { // always change dumb status inside write action. // This will ensure all active read actions are completed before the app goes dumb boolean startSuccess = @@ -239,14 +157,13 @@ public class DumbServiceImpl extends DumbService { catch (Throwable e) { LOG.error(e); } - finally { - try { - updateRunnable.run(); - } - catch (Throwable e) { - LOG.error("Failed to start background index update task", e); - return false; - } + + try { + startBackgroundProcess(); + } + catch (Throwable e) { + LOG.error("Failed to start background index update task", e); + return false; } return true; } @@ -365,140 +282,101 @@ public class DumbServiceImpl extends DumbService { }, modalityState, myProject.getDisposed()); } - private class IndexUpdateRunnable implements Runnable { - private final CacheUpdateRunner myAction; + private void startBackgroundProcess() { + ProgressManager.getInstance().run(new Task.Backgroundable(myProject, IdeBundle.message("progress.indexing"), false) { - public IndexUpdateRunnable(@NotNull CacheUpdateRunner action) { - myAction = action; + @Override + public void run(@NotNull final ProgressIndicator indicator) { + if (indicator instanceof ProgressIndicatorEx) { + ((ProgressIndicatorEx)indicator).addStateDelegate(new AppIconProgress()); + } + + final ProgressIndicator proxy = new DelegatingProgressIndicator(indicator); + + final ShutDownTracker shutdownTracker = ShutDownTracker.getInstance(); + final Thread self = Thread.currentThread(); + try { + HeavyProcessLatch.INSTANCE.processStarted(); + shutdownTracker.registerStopperThread(self); + runTasks(proxy); + } + catch (RuntimeException e) { + LOG.error(e); + throw e; + } + finally { + shutdownTracker.unregisterStopperThread(self); + HeavyProcessLatch.INSTANCE.processFinished(); + } + } + + private void runTasks(ProgressIndicator indicator) { + while (true) { + DumbModeTask task = getNextTask(); + if (task == null) break; + + try { + if (ApplicationManager.getApplication().isInternal()) LOG.info("Running dumb mode task: " + task); + indicator.checkCanceled(); + indicator.setIndeterminate(true); + indicator.setText(IdeBundle.message("progress.indexing.scanning")); + task.performInDumbMode(indicator); + } + catch (ProcessCanceledException ignored) { + } + catch (Throwable unexpected) { + LOG.error(unexpected); + } + } + } + + }); + } + + @Nullable + private DumbModeTask getNextTask() { + final Ref nextTask = Ref.create(); + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + if (myProject.isDisposed()) return; + if (myUpdatesQueue.isEmpty()) { + updateFinished(); + } else { + nextTask.set(myUpdatesQueue.pullFirst()); + } + } + }); + return nextTask.get(); + } + + private class AppIconProgress extends ProgressIndicatorBase { + double lastFraction; + + @Override + public void setFraction(final double fraction) { + if (fraction - lastFraction < 0.01d) return; + lastFraction = fraction; + UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override + public void run() { + AppIcon.getInstance().setProgress(myProject, "indexUpdate", AppIconScheme.Progress.INDEXING, fraction, true); + } + }); } @Override - public void run() { - ProgressManager.getInstance().run(new Task.Backgroundable(myProject, IdeBundle.message("progress.indexing"), false) { - + public void finish(@NotNull TaskInfo task) { + UIUtil.invokeLaterIfNeeded(new Runnable() { @Override - public void run(@NotNull final ProgressIndicator indicator) { - if (indicator instanceof ProgressIndicatorEx) { - ((ProgressIndicatorEx)indicator).addStateDelegate(new ProgressIndicatorBase() { - double lastFraction; - - @Override - public void setFraction(final double fraction) { - if (fraction - lastFraction < 0.01d) return; - lastFraction = fraction; - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - AppIcon.getInstance().setProgress(myProject, "indexUpdate", AppIconScheme.Progress.INDEXING, fraction, true); - } - }); - } - - @Override - public void finish(@NotNull TaskInfo task) { - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - AppIcon appIcon = AppIcon.getInstance(); - if (appIcon.hideProgress(myProject, "indexUpdate")) { - appIcon.requestAttention(myProject, false); - appIcon.setOkBadge(myProject, true); - } - } - }); - } - }); - } - - final ProgressIndicator proxy = new DelegatingProgressIndicator(indicator); - - final ShutDownTracker shutdownTracker = ShutDownTracker.getInstance(); - final Thread self = Thread.currentThread(); - try { - HeavyProcessLatch.INSTANCE.processStarted(); - shutdownTracker.registerStopperThread(self); - runAction(proxy, myAction); - } - catch (RuntimeException e) { - LOG.error(e); - throw e; - } - finally { - shutdownTracker.unregisterStopperThread(self); - HeavyProcessLatch.INSTANCE.processFinished(); - } - } - - private void runAction(ProgressIndicator indicator, CacheUpdateRunner updateRunner) { - while (updateRunner != null) { - try { - if (ApplicationManager.getApplication().isInternal()) LOG.info("Running dumb mode task: " + updateRunner); - indicator.checkCanceled(); - indicator.setIndeterminate(true); - indicator.setText(IdeBundle.message("progress.indexing.scanning")); - int count = updateRunner.queryNeededFiles(indicator); - - indicator.setIndeterminate(false); - indicator.setText(IdeBundle.message("progress.indexing.updating")); - if (count > 0) { - updateRunner.processFiles(indicator, true); - } - updateRunner.updatingDone(); - } - catch (ProcessCanceledException ignored) { - } - catch (Throwable unexpected) { - LOG.error(unexpected); - } - updateRunner = getNextUpdateRunner(); - } - } - - @Nullable - private CacheUpdateRunner getNextUpdateRunner() { - final BlockingQueue actionQueue = new LinkedBlockingQueue(); - UIUtil.invokeLaterIfNeeded(new DumbAwareRunnable() { - @Override - public void run() { - IndexUpdateRunnable nextRunnable = getNextUpdateFromQueue(); - try { - actionQueue.offer(nextRunnable == null ? NULL_ACTION : nextRunnable.myAction); - } - finally { - if (nextRunnable == null) { - updateFinished(); - } - } - } - }); - - // try to obtain the next action or terminate if no actions left - while (!myProject.isDisposed()) { - try { - CacheUpdateRunner ref = actionQueue.poll(500L, TimeUnit.MILLISECONDS); - if (ref != null) { - return ref == NULL_ACTION ? null : ref; - } - } - catch (InterruptedException e) { - LOG.info(e); - } - } - return null; - } - - @Nullable - private IndexUpdateRunnable getNextUpdateFromQueue() { - try { - return myUpdatesQueue.isEmpty()? null : myUpdatesQueue.pullFirst(); - } - catch (Throwable e) { - LOG.info(e); - return null; + public void run() { + AppIcon appIcon = AppIcon.getInstance(); + if (appIcon.hideProgress(myProject, "indexUpdate")) { + appIcon.requestAttention(myProject, false); + appIcon.setOkBadge(myProject, true); } } }); } } - } From 5bb01403b6cbda2ec24679088a19884c0d5cd9e7 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Tue, 17 Jun 2014 17:52:36 +0200 Subject: [PATCH 09/15] IDEA-126283 WideSelectionTreeUI poor paint performance --- .../util/ui/tree/WideSelectionTreeUI.java | 43 ++++++------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java index 579a42529359..ba0eb265655e 100644 --- a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java +++ b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java @@ -17,7 +17,6 @@ package com.intellij.util.ui.tree; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.SystemInfo; -import com.intellij.util.containers.ComparatorUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -49,7 +48,6 @@ public class WideSelectionTreeUI extends BasicTreeUI { @NotNull private final Condition myWideSelectionCondition; private boolean myWideSelection; private boolean myOldRepaintAllRowValue; - private boolean invertLineColor; private boolean myForceDontPaintLines = false; private boolean mySkinny = false; @@ -281,17 +279,15 @@ public class WideSelectionTreeUI extends BasicTreeUI { final boolean isExpanded, final boolean hasBeenExpanded, final boolean isLeaf) { - if (!shouldPaintLines()) return; - if (!UIUtil.isUnderAquaBasedLookAndFeel() && !UIUtil.isUnderDarcula() && !UIUtil.isUnderIntelliJLaF()) { - if (UIUtil.isUnderAlloyIDEALookAndFeel()) { - invertLineColor = tree.getSelectionModel().isRowSelected(row) && tree.hasFocus(); - } + if (shouldPaintLines()) { super.paintHorizontalPartOfLeg(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf); - invertLineColor = false; } } private boolean shouldPaintLines() { + if (UIUtil.isUnderAquaBasedLookAndFeel() || UIUtil.isUnderDarcula() || UIUtil.isUnderIntelliJLaF()) { + return false; + } return myForceDontPaintLines || !"None".equals(tree.getClientProperty("JTree.lineStyle")); } @@ -302,41 +298,26 @@ public class WideSelectionTreeUI extends BasicTreeUI { @Override protected void paintVerticalPartOfLeg(final Graphics g, final Rectangle clipBounds, final Insets insets, final TreePath path) { - if (!UIUtil.isUnderAquaBasedLookAndFeel() && !UIUtil.isUnderDarcula() && !UIUtil.isUnderIntelliJLaF() && shouldPaintLines()) { - invertLineColor = UIUtil.isUnderAlloyIDEALookAndFeel() && tree.hasFocus() && tree.getSelectionModel().isPathSelected(path); + if (shouldPaintLines()) { super.paintVerticalPartOfLeg(g, clipBounds, insets, path); - invertLineColor = false; } } @Override protected void paintVerticalLine(Graphics g, JComponent c, int x, int top, int bottom) { - if (!shouldPaintLines()) return; - if (tree.hasFocus() && UIUtil.isUnderAlloyIDEALookAndFeel()) { - int y0, y1 = top; - while (y1 < bottom) { - y0 = y1; - final int row = tree.getRowForPath(tree.getClosestPathForLocation(x, y0 + 1)); - invertLineColor = tree.isRowSelected(row); - g.setColor(getHashColor()); - final Rectangle bounds = tree.getRowBounds(row); - y1 = bounds.y + bounds.height; - super.paintVerticalLine(g, c, x, y0, Math.min(bottom, y1)); - } - invertLineColor = false; - } else { + if (shouldPaintLines()) { super.paintVerticalLine(g, c, x, top, bottom); } } @Override protected Color getHashColor() { - if (invertLineColor && !ComparatorUtil.equalsNullable(UIUtil.getTreeSelectionForeground(), UIUtil.getTreeForeground())) { - final Color c = UIUtil.getTreeSelectionForeground(); - if (c != null) { - return c.darker(); - } - } + //if (invertLineColor && !ComparatorUtil.equalsNullable(UIUtil.getTreeSelectionForeground(), UIUtil.getTreeForeground())) { + // final Color c = UIUtil.getTreeSelectionForeground(); + // if (c != null) { + // return c.darker(); + // } + //} return super.getHashColor(); } From 5ecd10d3aa75718a4ee9098ab0a31cf900df254e Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 17 Jun 2014 20:26:16 +0400 Subject: [PATCH 10/15] fixed PY-13296 Pycharm UI unresponsive do not lock UI in case we just want to send package statistics --- .../python/packaging/PyPIPackageUtil.java | 4 ++-- .../statistics/PyPackageUsagesCollector.java | 14 +++++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java b/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java index 43bb4a933c50..fbbdfa215e9c 100644 --- a/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java +++ b/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java @@ -259,8 +259,8 @@ public class PyPIPackageUtil { return packages; } - public Collection getPackageNames() throws IOException { - Map pyPIPackages = loadAndGetPackages(); + public Collection getPackageNames() { + Map pyPIPackages = getPyPIPackages(); ArrayList list = Lists.newArrayList(pyPIPackages.keySet()); Collections.sort(list); return list; diff --git a/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java b/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java index f0702937f732..f8b4adde5b33 100644 --- a/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java +++ b/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java @@ -30,8 +30,10 @@ import com.jetbrains.python.packaging.PyRequirement; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; -import java.io.IOException; -import java.util.*; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * @author yole @@ -51,13 +53,7 @@ public class PyPackageUsagesCollector extends AbstractApplicationUsagesCollector public void run() { List requirements = PyPackageManagerImpl.getRequirements(m); if (requirements != null) { - Collection packages; - try { - packages = new HashSet(PyPIPackageUtil.INSTANCE.getPackageNames()); - } - catch (IOException e) { - return; - } + Collection packages = new HashSet(PyPIPackageUtil.INSTANCE.getPackageNames()); for (PyRequirement requirement : requirements) { String name = requirement.getName(); if (packages.contains(name)) { From 4bbb63ef966ceea6e5f623ac68244c03a358f581 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 17 Jun 2014 18:57:19 +0200 Subject: [PATCH 11/15] fix dumb mode tasks run twice in headless mode --- .../src/com/intellij/openapi/project/DumbServiceImpl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java index bfdb8a6e4b6b..b72a7e0cc70e 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java @@ -118,7 +118,9 @@ public class DumbServiceImpl extends DumbService { private void scheduleCacheUpdate(@NotNull final DumbModeTask task, boolean forceDumbMode) { final Application application = ApplicationManager.getApplication(); - if (application.isUnitTestMode() || application.isHeadlessEnvironment() || !forceDumbMode && !myDumb && application.isReadAccessAllowed()) { + if (application.isUnitTestMode() || + application.isHeadlessEnvironment() || + !forceDumbMode && !myDumb && application.isReadAccessAllowed()) { final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); if (indicator != null) { indicator.pushState(); @@ -133,6 +135,7 @@ public class DumbServiceImpl extends DumbService { indicator.popState(); } } + return; } UIUtil.invokeLaterIfNeeded(new DumbAwareRunnable() { From 7b346dae4e57afe851ff4a16e18f7cb58f0926a1 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 17 Jun 2014 19:00:47 +0200 Subject: [PATCH 12/15] user data maps: notNull, minor equals() optimization --- .../util/src/com/intellij/util/keyFMap/OneElementFMap.java | 4 ++-- .../util/src/com/intellij/util/keyFMap/PairElementsFMap.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/util/src/com/intellij/util/keyFMap/OneElementFMap.java b/platform/util/src/com/intellij/util/keyFMap/OneElementFMap.java index d57d6903fd08..8bd2f343cb92 100644 --- a/platform/util/src/com/intellij/util/keyFMap/OneElementFMap.java +++ b/platform/util/src/com/intellij/util/keyFMap/OneElementFMap.java @@ -22,7 +22,7 @@ public class OneElementFMap implements KeyFMap { private final Key myKey; private final V myValue; - public OneElementFMap(Key key, @NotNull V value) { + public OneElementFMap(@NotNull Key key, @NotNull V value) { myKey = key; myValue = value; } @@ -71,7 +71,7 @@ public class OneElementFMap implements KeyFMap { OneElementFMap map = (OneElementFMap)o; - if (!myKey.equals(map.myKey)) return false; + if (myKey != map.myKey) return false; if (!myValue.equals(map.myValue)) return false; return true; diff --git a/platform/util/src/com/intellij/util/keyFMap/PairElementsFMap.java b/platform/util/src/com/intellij/util/keyFMap/PairElementsFMap.java index 800032e50456..bb8b8d0ace15 100644 --- a/platform/util/src/com/intellij/util/keyFMap/PairElementsFMap.java +++ b/platform/util/src/com/intellij/util/keyFMap/PairElementsFMap.java @@ -24,7 +24,7 @@ class PairElementsFMap implements KeyFMap { private final Object value1; private final Object value2; - PairElementsFMap(Key key1, @NotNull Object value1, Key key2, @NotNull Object value2) { + PairElementsFMap(@NotNull Key key1, @NotNull Object value1, @NotNull Key key2, @NotNull Object value2) { this.key1 = key1; this.value1 = value1; this.key2 = key2; From 88c8ac79e5b39fc25a129ae74835d1173e96570c Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 17 Jun 2014 19:43:42 +0200 Subject: [PATCH 13/15] dfa: handle variable comparisons to unknown not-null values --- .../dataFlow/DfaMemoryStateImpl.java | 9 ++++++++- .../dataFlow/value/DfaRelationValue.java | 5 ++++- .../dataFlow/fixture/ComparingNullToNotNull.java | 14 ++++++++++++++ .../fixture/ComparingNullableToNullable.java | 16 ++++++++++++++++ .../fixture/ComparingNullableToUnknown.java | 16 ++++++++++++++++ .../codeInspection/DataFlowInspectionTest.java | 3 +++ 6 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullToNotNull.java create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToNullable.java create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToUnknown.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index 3b44c82f9398..1b6d1dfedfec 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -583,7 +583,14 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (dfaLeft instanceof DfaVariableValue) { DfaVariableValue dfaVar = (DfaVariableValue)dfaLeft; if (isUnknownState(dfaVar)) return true; - + + if (!dfaRelation.isInstanceOf()) { + if (((DfaTypeValue)dfaRight).isNotNull() && isNull(dfaVar)) { + return isNegated; + } + return true; + } + if (isNegated) { DfaVariableState newState = getVariableState(dfaVar).withNotInstanceofValue((DfaTypeValue)dfaRight); if (newState != null) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java index 8343fc9e6a2c..3e70b2d4b673 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java @@ -52,7 +52,6 @@ public class DfaRelationValue extends DfaValue { } public DfaRelationValue createRelation(DfaValue dfaLeft, DfaValue dfaRight, IElementType relation, boolean negated) { - if (dfaRight instanceof DfaTypeValue && INSTANCEOF_KEYWORD != relation) return null; if (PLUS == relation) return null; if (dfaLeft instanceof DfaVariableValue || dfaLeft instanceof DfaBoxedValue || dfaLeft instanceof DfaUnboxedValue @@ -169,6 +168,10 @@ public class DfaRelationValue extends DfaValue { return myRelation == EQEQ && myIsNegated || myRelation == GT && !myIsNegated || myRelation == GE && myIsNegated; } + public boolean isInstanceOf() { + return myRelation == INSTANCEOF_KEYWORD; + } + @NonNls public String toString() { return (isNegated() ? "not " : "") + myLeftOperand + " " + myRelation + " " + myRightOperand; } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullToNotNull.java b/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullToNotNull.java new file mode 100644 index 000000000000..a9f17f7e9a06 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullToNotNull.java @@ -0,0 +1,14 @@ +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +class Bar3 { + + public void foo(@Nullable Object element) { + final String elementType = element != null ? element.toString() : null; + if (elementType == "") { + System.out.println(element.hashCode()); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToNullable.java b/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToNullable.java new file mode 100644 index 000000000000..5e3ce3c0b69b --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToNullable.java @@ -0,0 +1,16 @@ +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +class Bar3 { + + public void foo(@Nullable Object element) { + final String elementType = element != null ? element.toString() : null; + if (elementType == nullableString()) { + System.out.println(element.hashCode()); + } + } + + @Nullable String nullableString() { return null; } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToUnknown.java b/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToUnknown.java new file mode 100644 index 000000000000..b15c6c7a52f7 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToUnknown.java @@ -0,0 +1,16 @@ +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +class Bar3 { + + public void foo(@Nullable Object element) { + final String elementType = element != null ? element.toString() : null; + if (elementType == someString()) { + System.out.println(element.hashCode()); + } + } + + String someString() { return null; } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index d15527e3c49c..833b5196d74a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -71,6 +71,9 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { public void testGeneratedEquals() throws Throwable { doTest(); } public void testIDEA84489() throws Throwable { doTest(); } + public void testComparingNullToNotNull() { doTest(); } + public void testComparingNullableToNullable() { doTest(); } + public void testComparingNullableToUnknown() { doTest(); } public void testComparingToNotNullShouldNotAffectNullity() throws Throwable { doTest(); } public void testComparingToNullableShouldNotAffectNullity() throws Throwable { doTest(); } public void testStringTernaryAlwaysTrue() throws Throwable { doTest(); } From 5cac2764f67d227b10e8e64eca7097f639eed4dc Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Wed, 18 Jun 2014 09:49:19 +0200 Subject: [PATCH 14/15] Platform: OS X scrollbars: returned non-os x disabling logic --- .../src/com/intellij/ui/components/JBScrollPane.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java index 878434ad467a..83944a51755d 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java @@ -268,6 +268,8 @@ public class JBScrollPane extends JScrollPane { } private static boolean isOverlaidScrollbar(@Nullable JScrollBar scrollbar) { + if (!ButtonlessScrollBarUI.isMacOverlayScrollbarSupported()) return false; + ScrollBarUI vsbUI = scrollbar == null ? null : scrollbar.getUI(); return vsbUI instanceof ButtonlessScrollBarUI && !((ButtonlessScrollBarUI)vsbUI).alwaysShowTrack(); } From fe1ff57dd3d2fa1f31a7b9666641903190e2f41c Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 18 Jun 2014 10:07:32 +0200 Subject: [PATCH 15/15] restore xml suppressions until EL, etc would provide its own suppressor --- .../XmlSuppressableInspectionTool.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java b/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java index 2a942b9f56af..9521814649e2 100644 --- a/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java +++ b/xml/xml-psi-api/src/com/intellij/codeInspection/XmlSuppressableInspectionTool.java @@ -26,14 +26,25 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool { +public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool implements BatchSuppressableTool { @NonNls static final String ALL = "ALL"; + @NotNull + @Override + public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) { + return getSuppressFixes(getID()); + } + public static SuppressQuickFix[] getSuppressFixes(final String shortName) { final String id = HighlightDisplayKey.find(shortName).getID(); return new SuppressQuickFix[]{new SuppressTagStatic(id), new SuppressForFile(id), new SuppressAllForFile()}; } + @Override + public boolean isSuppressedFor(@NotNull final PsiElement element) { + return XmlSuppressionProvider.isSuppressed(element, getID()); + } + public class SuppressTag extends SuppressTagStatic { public SuppressTag() { super(getID());