From a6657f836d2de9f0751d990f133a50f69e7bbc59 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 18 May 2012 13:09:28 +0400 Subject: [PATCH] rewire logic for ignoring changes in whitespace and comment into the ChangeLocalityDetector. --- .../impl/JavaChangeLocalityDetector.java | 11 ++++-- .../daemon/ChangeLocalityDetector.java | 10 +++++- .../impl/DefaultChangeLocalityDetector.java | 35 ++++++++++++++++++ .../daemon/impl/PsiChangeHandler.java | 24 ++++++------- .../src/META-INF/XmlPlugin.xml | 4 +-- .../xslt/impl/XsltChangeLocalityDetector.java | 3 +- resources/src/META-INF/IdeaPlugin.xml | 1 + .../xml/XmlChangeLocalityDetector.java | 36 +++++++++++++++++++ .../DefaultXmlSuppressionProvider.java | 9 ++++- 9 files changed, 112 insertions(+), 21 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DefaultChangeLocalityDetector.java create mode 100644 xml/impl/src/com/intellij/xml/XmlChangeLocalityDetector.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaChangeLocalityDetector.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaChangeLocalityDetector.java index 6a8f8244faca..1f06435e398a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaChangeLocalityDetector.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaChangeLocalityDetector.java @@ -21,15 +21,20 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeInsight.daemon.ChangeLocalityDetector; import com.intellij.psi.*; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class JavaChangeLocalityDetector implements ChangeLocalityDetector { @Override @Nullable - public PsiElement getChangeHighlightingDirtyScopeFor(final PsiElement element) { + public PsiElement getChangeHighlightingDirtyScopeFor(@NotNull final PsiElement element) { + // optimization PsiElement parent = element.getParent(); - if (element instanceof PsiCodeBlock && parent instanceof PsiMethod && !((PsiMethod)parent).isConstructor() && - parent.getParent() instanceof PsiClass && !(parent.getParent() instanceof PsiAnonymousClass)) { + if (element instanceof PsiCodeBlock + && parent instanceof PsiMethod + && !((PsiMethod)parent).isConstructor() + && parent.getParent() instanceof PsiClass + && !(parent.getParent() instanceof PsiAnonymousClass)) { // for changes inside method, rehighlight codeblock only // do not use this optimization for constructors and class initializers - to update non-initialized fields return parent; diff --git a/platform/lang-api/src/com/intellij/codeInsight/daemon/ChangeLocalityDetector.java b/platform/lang-api/src/com/intellij/codeInsight/daemon/ChangeLocalityDetector.java index b80a4b6fc9be..fedbd19f2f48 100644 --- a/platform/lang-api/src/com/intellij/codeInsight/daemon/ChangeLocalityDetector.java +++ b/platform/lang-api/src/com/intellij/codeInsight/daemon/ChangeLocalityDetector.java @@ -20,9 +20,17 @@ package com.intellij.codeInsight.daemon; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public interface ChangeLocalityDetector { + /** + * @param changedElement + * @return the psi element (ancestor of the changedElement) which should be re-highlighted, or null if unsure. + * e.g. in Java we re-highlight enclosing code block only when element inside has changed. + * Note: do not traverse PSI tree upwards here, + * since this ChangeLocalityDetector will be called for the changed element and all its parents anyway. + */ @Nullable - PsiElement getChangeHighlightingDirtyScopeFor(PsiElement changedElement); + PsiElement getChangeHighlightingDirtyScopeFor(@NotNull PsiElement changedElement); } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DefaultChangeLocalityDetector.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DefaultChangeLocalityDetector.java new file mode 100644 index 000000000000..a822811aa845 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DefaultChangeLocalityDetector.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2012 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; + +import com.intellij.codeInsight.daemon.ChangeLocalityDetector; +import com.intellij.codeInspection.SuppressionUtil; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; +import org.jetbrains.annotations.NotNull; + +public class DefaultChangeLocalityDetector implements ChangeLocalityDetector { + @Override + public PsiElement getChangeHighlightingDirtyScopeFor(@NotNull PsiElement changedElement) { + if (changedElement instanceof PsiWhiteSpace || + changedElement instanceof PsiComment + && !changedElement.getText().contains(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME)) { + return changedElement; + } + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java index f148691cd732..956f39823ba5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiChangeHandler.java @@ -17,7 +17,6 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.codeInsight.daemon.ChangeLocalityDetector; -import com.intellij.codeInspection.SuppressionUtil; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; @@ -214,18 +213,9 @@ public class PsiChangeHandler extends PsiTreeChangeAdapter implements Disposable return; } - // optimization - if (whitespaceOptimizationAllowed && UpdateHighlightersUtil.isWhitespaceOptimizationAllowed(document)) { - if (child instanceof PsiWhiteSpace || - child instanceof PsiComment && !child.getText().contains(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME)) { - myFileStatusMap.markFileScopeDirty(document, child.getTextRange(), fileLength); - return; - } - } - - PsiElement element = child; + PsiElement element = whitespaceOptimizationAllowed && UpdateHighlightersUtil.isWhitespaceOptimizationAllowed(document) ? child : child.getParent(); while (true) { - if (element instanceof PsiFile || element instanceof PsiDirectory) { + if (element == null || element instanceof PsiFile || element instanceof PsiDirectory) { myFileStatusMap.markAllFilesDirty(); return; } @@ -242,10 +232,18 @@ public class PsiChangeHandler extends PsiTreeChangeAdapter implements Disposable @Nullable private static PsiElement getChangeHighlightingScope(PsiElement element) { + DefaultChangeLocalityDetector defaultDetector = null; for (ChangeLocalityDetector detector : Extensions.getExtensions(EP_NAME)) { + if (detector instanceof DefaultChangeLocalityDetector) { + // run default detector last + assert defaultDetector == null : defaultDetector; + defaultDetector = (DefaultChangeLocalityDetector)detector; + continue; + } final PsiElement scope = detector.getChangeHighlightingDirtyScopeFor(element); if (scope != null) return scope; } - return null; + assert defaultDetector != null : "com.intellij.codeInsight.daemon.impl.DefaultChangeLocalityDetector is unregistered"; + return defaultDetector.getChangeHighlightingDirtyScopeFor(element); } } diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index 6465f1f168f9..834e6e03ed0c 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -404,7 +404,7 @@ - + + diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltChangeLocalityDetector.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltChangeLocalityDetector.java index c72f6ac58eb8..5b7dedcecae3 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltChangeLocalityDetector.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/impl/XsltChangeLocalityDetector.java @@ -22,6 +22,7 @@ import com.intellij.psi.xml.XmlElementType; import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlToken; import org.intellij.lang.xpath.xslt.XsltSupport; +import org.jetbrains.annotations.NotNull; /* * Created by IntelliJ IDEA. @@ -30,7 +31,7 @@ import org.intellij.lang.xpath.xslt.XsltSupport; */ public class XsltChangeLocalityDetector implements ChangeLocalityDetector { @Override - public PsiElement getChangeHighlightingDirtyScopeFor(PsiElement changedElement) { + public PsiElement getChangeHighlightingDirtyScopeFor(@NotNull PsiElement changedElement) { try { if (changedElement instanceof XmlToken && changedElement.getNode().getElementType() == XmlElementType.XML_ATTRIBUTE_VALUE_TOKEN) { final PsiElement grandParent = changedElement.getParent().getParent(); diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index cb3175edc39c..82372a8498d0 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -969,6 +969,7 @@ + diff --git a/xml/impl/src/com/intellij/xml/XmlChangeLocalityDetector.java b/xml/impl/src/com/intellij/xml/XmlChangeLocalityDetector.java new file mode 100644 index 000000000000..fb65aa55965d --- /dev/null +++ b/xml/impl/src/com/intellij/xml/XmlChangeLocalityDetector.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.xml; + +import com.intellij.codeInsight.daemon.ChangeLocalityDetector; +import com.intellij.codeInspection.DefaultXmlSuppressionProvider; +import com.intellij.lang.xml.XMLLanguage; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; + +public class XmlChangeLocalityDetector implements ChangeLocalityDetector { + @Override + public PsiElement getChangeHighlightingDirtyScopeFor(@NotNull PsiElement changedElement) { + // rehighlight everything when inspection suppress comment changed + if (changedElement.getLanguage() instanceof XMLLanguage + && changedElement instanceof PsiComment + && changedElement.getText().contains(DefaultXmlSuppressionProvider.SUPPRESS_MARK)) { + return changedElement.getContainingFile(); + } + return null; + } +} diff --git a/xml/openapi/src/com/intellij/codeInspection/DefaultXmlSuppressionProvider.java b/xml/openapi/src/com/intellij/codeInspection/DefaultXmlSuppressionProvider.java index f1ce3969dfc2..6aa1a22ad909 100644 --- a/xml/openapi/src/com/intellij/codeInspection/DefaultXmlSuppressionProvider.java +++ b/xml/openapi/src/com/intellij/codeInspection/DefaultXmlSuppressionProvider.java @@ -37,16 +37,20 @@ import org.jetbrains.annotations.Nullable; */ public class DefaultXmlSuppressionProvider extends XmlSuppressionProvider { + public static final String SUPPRESS_MARK = "suppress"; + @Override public boolean isProviderAvailable(PsiFile file) { return true; } + @Override public boolean isSuppressedFor(PsiElement element, String inspectionId) { final XmlTag tag = element instanceof XmlFile ? ((XmlFile)element).getRootTag() : PsiTreeUtil.getContextOfType(element, XmlTag.class, false); return tag != null && findSuppression(tag, inspectionId, element) != null; } + @Override public void suppressForFile(PsiElement element, String inspectionId) { final PsiFile file = element.getContainingFile(); final XmlDocument document = ((XmlFile)file).getDocument(); @@ -55,6 +59,7 @@ public class DefaultXmlSuppressionProvider extends XmlSuppressionProvider { suppress(file, findFileSuppression(anchor, null, element), inspectionId, anchor.getTextRange().getStartOffset()); } + @Override public void suppressForTag(PsiElement element, String inspectionId) { final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class); assert tag != null; @@ -140,7 +145,9 @@ public class DefaultXmlSuppressionProvider extends XmlSuppressionProvider { @NonNls protected String getPrefix() { - return "