From b2a8cb5f480a19357c80d42e96ea49d25b3ef93c Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 14 Dec 2017 16:23:35 +0300 Subject: [PATCH] assert that rangeInElement is inside the descriptor range to avoid surprising "index out of range" exceptions --- .../java18api/Java8MapForEachInspection.java | 14 ++++--- .../daemon/impl/UpdateHighlightersUtil.java | 2 +- .../codeInspection/ProblemDescriptorBase.java | 39 +++++++++++-------- .../com/intellij/openapi/util/TextRange.java | 4 +- .../validation/UnsupportedFeatures.java | 2 +- ...omElementResolveProblemDescriptorImpl.java | 14 ++----- 6 files changed, 40 insertions(+), 35 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInspection/java18api/Java8MapForEachInspection.java b/java/java-impl/src/com/intellij/codeInspection/java18api/Java8MapForEachInspection.java index a520bf1890b8..ccae441b2c3a 100644 --- a/java/java-impl/src/com/intellij/codeInspection/java18api/Java8MapForEachInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/java18api/Java8MapForEachInspection.java @@ -94,13 +94,16 @@ public class Java8MapForEachInspection extends AbstractBaseJavaLocalInspectionTo TextRange range; PsiJavaToken rParenth = loop.getRParenth(); PsiElement firstChild = loop.getFirstChild(); + PsiElement toHighlight; if (wholeStatement && rParenth != null) { - range = new TextRange(0, rParenth.getStartOffsetInParent() + 1); + toHighlight = loop; + range = new TextRange(firstChild.getStartOffsetInParent(), rParenth.getStartOffsetInParent() + 1); } else { + toHighlight = firstChild; range = new TextRange(0, firstChild.getTextLength()); } - holder.registerProblem(loop.getFirstChild(), InspectionsBundle.message("inspection.map.foreach.message"), + holder.registerProblem(toHighlight, InspectionsBundle.message("inspection.map.foreach.message"), type, range, new ReplaceWithMapForEachFix()); } } @@ -118,8 +121,9 @@ public class Java8MapForEachInspection extends AbstractBaseJavaLocalInspectionTo @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { PsiElement element = descriptor.getStartElement(); - if (element.getParent() instanceof PsiForeachStatement) { - fixInForeach((PsiForeachStatement)element.getParent()); + PsiElement foreach = element instanceof PsiForeachStatement ? element : element.getParent(); + if (foreach instanceof PsiForeachStatement) { + fixInForeach((PsiForeachStatement)foreach); return; } PsiMethodCallExpression call = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class); @@ -198,7 +202,7 @@ public class Java8MapForEachInspection extends AbstractBaseJavaLocalInspectionTo final PsiType myType; String myName; - public ParameterCandidate(PsiType entryType, boolean isKey) { + ParameterCandidate(PsiType entryType, boolean isKey) { myName = isKey ? "key" : "value"; myType = GenericsUtil .getVariableTypeByExpressionType(PsiUtil.substituteTypeParameter(entryType, JAVA_UTIL_MAP_ENTRY, isKey ? 0 : 1, true)); diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java index 2fda891c0bac..c8ac1ba40fa4 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java @@ -335,7 +335,7 @@ public class UpdateHighlightersUtil { info.setGroup(group); int layer = getLayer(info, severityRegistrar); - RangeHighlighterEx highlighter = infosToRemove == null ? null : (RangeHighlighterEx)infosToRemove.pickupHighlighterFromGarbageBin(info.startOffset, info.endOffset, layer); + RangeHighlighterEx highlighter = infosToRemove == null ? null : (RangeHighlighterEx)infosToRemove.pickupHighlighterFromGarbageBin(infoStartOffset, infoEndOffset, layer); final TextRange finalInfoRange = new TextRange(infoStartOffset, infoEndOffset); final TextAttributes infoAttributes = info.getTextAttributes(psiFile, colorsScheme); diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ProblemDescriptorBase.java b/platform/analysis-impl/src/com/intellij/codeInspection/ProblemDescriptorBase.java index c43f0bb8cf5e..67d6692ef39e 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ProblemDescriptorBase.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ProblemDescriptorBase.java @@ -69,7 +69,17 @@ public class ProblemDescriptorBase extends CommonProblemDescriptorImpl implement && endElementRange != null && startElementRange.getStartOffset() >= endElementRange.getEndOffset()) { if (!(startElement instanceof PsiFile && endElement instanceof PsiFile)) { - LOG.error("Empty PSI elements should not be passed to createDescriptor. Start: " + startElement + ", end: " + endElement + ", startContainingFile: " + startContainingFile); + LOG.error("Empty PSI elements must not be passed to createDescriptor. Start: " + startElement + ", end: " + endElement + ", startContainingFile: " + startContainingFile); + } + } + if (rangeInElement != null && startElementRange != null && endElementRange != null) { + TextRange.assertProperRange(rangeInElement); + if (rangeInElement.getEndOffset() > endElementRange.getEndOffset() - startElementRange.getStartOffset()) { + LOG.error("Argument rangeInElement " + rangeInElement + " endOffset"+ + " must not exceed descriptor text range " + + "(" + startElementRange.getStartOffset() + + ", " + endElementRange.getEndOffset() + ")" + + " length ("+(endElementRange.getEndOffset()-startElementRange.getStartOffset())+")."); } } @@ -189,23 +199,20 @@ public class ProblemDescriptorBase extends CommonProblemDescriptorImpl implement if (startRange == null) { return null; } - if (startElement == endElement) { - if (isAfterEndOfLine()) { - int endOffset = myTextRangeInElement != null ? startRange.getStartOffset() + myTextRangeInElement.getEndOffset() - : startRange.getEndOffset(); - return new TextRange(endOffset, endOffset); - } - if (myTextRangeInElement != null) { - return new TextRange(startRange.getStartOffset() + myTextRangeInElement.getStartOffset(), - startRange.getStartOffset() + myTextRangeInElement.getEndOffset()); - } - return startRange; + + if (startElement != endElement) { + TextRange endRange = getAnnotationRange(endElement); + if (endRange == null) return null; + startRange = startRange.union(endRange); } - TextRange endRange = getAnnotationRange(endElement); - if (endRange == null) { - return null; + else if (myTextRangeInElement != null) { + startRange = startRange.cutOut(myTextRangeInElement); } - return new TextRange(startRange.getStartOffset(), endRange.getEndOffset()); + if (isAfterEndOfLine()) { + int endOffset = startRange.getEndOffset(); + return new TextRange(endOffset, endOffset); + } + return startRange; } public Navigatable getNavigatable() { diff --git a/platform/util/src/com/intellij/openapi/util/TextRange.java b/platform/util/src/com/intellij/openapi/util/TextRange.java index 99510f32d08d..fa94e2805101 100644 --- a/platform/util/src/com/intellij/openapi/util/TextRange.java +++ b/platform/util/src/com/intellij/openapi/util/TextRange.java @@ -120,8 +120,8 @@ public class TextRange implements Segment, Serializable { @NotNull public TextRange cutOut(@NotNull TextRange subRange) { - assert subRange.getStartOffset() <= getLength() : subRange + "; this="+this; - assert subRange.getEndOffset() <= getLength() : subRange + "; this="+this; + assert subRange.getStartOffset() <= getLength() : "SubRange: " + subRange + "; this=" + this; + assert subRange.getEndOffset() <= getLength() : "SubRange: " + subRange + "; this=" + this; assertProperRange(subRange); return new TextRange(myStartOffset + subRange.getStartOffset(), Math.min(myEndOffset, myStartOffset + subRange.getEndOffset())); diff --git a/python/src/com/jetbrains/python/validation/UnsupportedFeatures.java b/python/src/com/jetbrains/python/validation/UnsupportedFeatures.java index 1f315ba9bed1..e29917840c76 100644 --- a/python/src/com/jetbrains/python/validation/UnsupportedFeatures.java +++ b/python/src/com/jetbrains/python/validation/UnsupportedFeatures.java @@ -77,7 +77,7 @@ public class UnsupportedFeatures extends CompatibilityVisitor { @NotNull private static IntentionAction createIntention(@NotNull PsiElement node, @NotNull String message, @NotNull LocalQuickFix localQuickFix) { - return createIntention(node, node.getTextRange(), message, localQuickFix); + return createIntention(node, null, message, localQuickFix); } @NotNull diff --git a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementResolveProblemDescriptorImpl.java b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementResolveProblemDescriptorImpl.java index e9b436ef40af..7681ec56de1e 100644 --- a/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementResolveProblemDescriptorImpl.java +++ b/xml/dom-impl/src/com/intellij/util/xml/highlighting/DomElementResolveProblemDescriptorImpl.java @@ -21,7 +21,6 @@ import com.intellij.codeInspection.ProblemsHolder; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.UnfairTextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference; @@ -35,7 +34,9 @@ import org.jetbrains.annotations.NotNull; class DomElementResolveProblemDescriptorImpl extends DomElementProblemDescriptorImpl implements DomElementResolveProblemDescriptor { @NotNull private final PsiReference myReference; - public DomElementResolveProblemDescriptorImpl(@NotNull final GenericDomValue domElement, @NotNull final PsiReference reference, LocalQuickFix... quickFixes) { + DomElementResolveProblemDescriptorImpl(@NotNull final GenericDomValue domElement, + @NotNull final PsiReference reference, + LocalQuickFix... quickFixes) { super(domElement, reference instanceof FileReference ? ProblemsHolder.unresolvedReferenceMessage(reference) : XmlHighlightVisitor.getErrorDescription(reference), HighlightSeverity.ERROR, quickFixes); myReference = reference; } @@ -58,14 +59,7 @@ class DomElementResolveProblemDescriptorImpl extends DomElementProblemDescriptor final PsiReference reference = myReference; PsiElement element = reference.getElement(); if (element instanceof XmlAttributeValue && element.getTextLength() == 0) return NO_PROBLEM; - - final TextRange referenceRange = reference.getRangeInElement(); - if (referenceRange.isEmpty()) { - int startOffset = referenceRange.getStartOffset(); - return element instanceof XmlAttributeValue - ? Pair.create((TextRange)new UnfairTextRange(startOffset - 1, startOffset + 1), element) - : Pair.create(TextRange.from(startOffset, 1), element); - } + TextRange referenceRange = reference.getRangeInElement(); return Pair.create(referenceRange, element); } }