diff options
author | Mickael Istria | 2019-04-01 22:43:35 +0000 |
---|---|---|
committer | Mickael Istria | 2019-04-01 22:57:59 +0000 |
commit | ed76a4ee96d3a0ea40b6bf4d1447f2af49cb9f7f (patch) | |
tree | ccf16a832d3b255db597d44103c2c19bfea07be6 | |
parent | 4b9a8a739f42da547975427154744c981d0811ba (diff) | |
download | eclipse.platform.text-ed76a4ee96d3a0ea40b6bf4d1447f2af49cb9f7f.tar.gz eclipse.platform.text-ed76a4ee96d3a0ea40b6bf4d1447f2af49cb9f7f.tar.xz eclipse.platform.text-ed76a4ee96d3a0ea40b6bf4d1447f2af49cb9f7f.zip |
Bug 546020 - [code mining] "Index out of Bounds" when inline w/ foldingI20190407-1800I20190406-1800I20190405-1800I20190404-1800I20190403-1800I20190402-1800
Change-Id: I7b10e2d8122372bec5452225313142cf6ec58f3c
Signed-off-by: Mickael Istria <mistria@redhat.com>
11 files changed, 236 insertions, 24 deletions
diff --git a/org.eclipse.jface.text.tests/META-INF/MANIFEST.MF b/org.eclipse.jface.text.tests/META-INF/MANIFEST.MF index 7194ac38c6b..4d334bb3040 100644 --- a/org.eclipse.jface.text.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.jface.text.tests/META-INF/MANIFEST.MF @@ -2,11 +2,12 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Plugin.name Bundle-SymbolicName: org.eclipse.jface.text.tests -Bundle-Version: 3.11.600.qualifier +Bundle-Version: 3.11.700.qualifier Bundle-Vendor: %Plugin.providerName Bundle-Localization: plugin Export-Package: org.eclipse.jface.text.tests, + org.eclipse.jface.text.tests.codemining, org.eclipse.jface.text.tests.contentassist, org.eclipse.jface.text.tests.reconciler, org.eclipse.jface.text.tests.rules, diff --git a/org.eclipse.jface.text.tests/pom.xml b/org.eclipse.jface.text.tests/pom.xml index 25643b9d0d2..18ea858c59d 100644 --- a/org.eclipse.jface.text.tests/pom.xml +++ b/org.eclipse.jface.text.tests/pom.xml @@ -19,7 +19,7 @@ </parent> <groupId>org.eclipse.jface</groupId> <artifactId>org.eclipse.jface.text.tests</artifactId> - <version>3.11.600-SNAPSHOT</version> + <version>3.11.700-SNAPSHOT</version> <packaging>eclipse-test-plugin</packaging> <properties> <testSuite>${project.artifactId}</testSuite> diff --git a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java index 7e822ffd8cf..d35ff7e74e3 100644 --- a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java +++ b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/JFaceTextTestSuite.java @@ -17,6 +17,8 @@ import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; +import org.eclipse.jface.text.tests.codemining.CodeMiningTest; +import org.eclipse.jface.text.tests.codemining.CodeMiningProjectionViewerTest; import org.eclipse.jface.text.tests.contentassist.AsyncContentAssistTest; import org.eclipse.jface.text.tests.reconciler.AbstractReconcilerTest; import org.eclipse.jface.text.tests.rules.DefaultPartitionerTest; @@ -55,7 +57,8 @@ import org.eclipse.jface.text.tests.templates.persistence.TemplatePersistenceDat WordRuleTest.class, TemplatePersistenceDataTest.class, - CodeMiningTest.class + CodeMiningTest.class, + CodeMiningProjectionViewerTest.class }) public class JFaceTextTestSuite { // see @SuiteClasses diff --git a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/ScreenshotOnFailureRule.java b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/ScreenshotOnFailureRule.java index 3deb5799298..da2da95943f 100644 --- a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/ScreenshotOnFailureRule.java +++ b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/ScreenshotOnFailureRule.java @@ -17,7 +17,7 @@ import org.junit.rules.TestWatcher; import org.eclipse.test.Screenshots; -final class ScreenshotOnFailureRule extends TestWatcher { +public final class ScreenshotOnFailureRule extends TestWatcher { @Override protected void failed(Throwable e, org.junit.runner.Description description) { Screenshots.takeScreenshot(description.getTestClass(), description.getMethodName()); diff --git a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningProjectionViewerTest.java b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningProjectionViewerTest.java new file mode 100644 index 00000000000..9e06ba19ba8 --- /dev/null +++ b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningProjectionViewerTest.java @@ -0,0 +1,162 @@ +/** + * Copyright (c) 2019 Red Hat Inc., and others + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * - Mickael Istria (Red Hat Inc.) + */ +package org.eclipse.jface.text.tests.codemining; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.Bundle; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Shell; + +import org.eclipse.core.runtime.ILog; +import org.eclipse.core.runtime.ILogListener; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.codemining.ICodeMining; +import org.eclipse.jface.text.codemining.ICodeMiningProvider; +import org.eclipse.jface.text.codemining.LineContentCodeMining; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.AnnotationPainter; +import org.eclipse.jface.text.source.IAnnotationAccess; +import org.eclipse.jface.text.source.ISharedTextColors; +import org.eclipse.jface.text.source.projection.ProjectionAnnotation; +import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel; +import org.eclipse.jface.text.source.projection.ProjectionSupport; +import org.eclipse.jface.text.source.projection.ProjectionViewer; +import org.eclipse.jface.text.tests.util.DisplayHelper; + +public class CodeMiningProjectionViewerTest { + + private final class RepeatLettersCodeMiningProvider implements ICodeMiningProvider { + @Override + public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer, IProgressMonitor monitor) { + List<LineContentCodeMining> codeMinings = new ArrayList<>(); + for (int i = 0; i < viewer.getDocument().getLength(); i++) { + try { + char c= viewer.getDocument().getChar(i); + if (Character.isLetter(c)) { + codeMinings.add(new StaticContentLineCodeMining(i, c, this)); + } + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + return CompletableFuture.completedFuture(codeMinings); + } + + @Override + public void dispose() { + } + } + + private Shell fParent; + private ProjectionViewer fViewer; + + @Before + public void setUp() { + fParent= new Shell(); + fParent.setSize(500, 200); + fParent.setLayout(new FillLayout()); + fViewer= new ProjectionViewer(fParent, null, null, false, SWT.NONE); + IAnnotationAccess annotationAccess = new IAnnotationAccess() { + @Override + public Object getType(Annotation annotation) { + return annotation.getType(); + } + + @Override + public boolean isMultiLine(Annotation annotation) { + return true; + } + + @Override + public boolean isTemporary(Annotation annotation) { + return true; + } + }; + // code minings + AnnotationPainter painter = new AnnotationPainter(fViewer, annotationAccess); + fViewer.addPainter(painter); + fViewer.setCodeMiningAnnotationPainter(painter); + // projection/folding + fViewer.setDocument(new Document(), new ProjectionAnnotationModel()); + ProjectionSupport projectionSupport = new ProjectionSupport(fViewer, annotationAccess, new ISharedTextColors() { + @Override + public Color getColor(RGB rgb) { + return null; + } + + @Override + public void dispose() { + } + }); + projectionSupport.install(); + fViewer.doOperation(ProjectionViewer.TOGGLE); + } + + @After + public void tearDown() { + fParent.dispose(); + } + + @Test + public void testCollapse() throws Exception { + fViewer.setCodeMiningProviders(new ICodeMiningProvider[] { + new RepeatLettersCodeMiningProvider() + }); + fViewer.getDocument().set("1a\n2a\n3a\n4a\n5a\n6a\n"); + ProjectionAnnotation annotation= new ProjectionAnnotation(true); + fViewer.getProjectionAnnotationModel().addAnnotation(annotation, new Position(0, fViewer.getDocument().getLineOffset(4))); + fViewer.doOperation(ProjectionViewer.COLLAPSE_ALL); + fViewer.updateCodeMinings(); + fParent.open(); + + Bundle bundle = Platform.getBundle("org.eclipse.ui.workbench"); + ILog log = null; + AtomicReference<IStatus> logError = new AtomicReference<>(); + ILogListener logListener= (status, plugin) -> { + logError.set(status); + }; + if (bundle != null && bundle.getState() == Bundle.ACTIVE) { + log = Platform.getLog(bundle); + log.addLogListener(logListener); + } + try { + // without workbench, next line throws Exception directly + DisplayHelper.sleep(fParent.getDisplay(), 1000); + Assert.assertNull(logError.get()); + } finally { + if (log != null) { + log.removeLogListener(logListener); + } + } + } +} diff --git a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/CodeMiningTest.java b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningTest.java index a02f64b5b03..cac5fde14ae 100644 --- a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/CodeMiningTest.java +++ b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/CodeMiningTest.java @@ -11,7 +11,7 @@ * Contributors: * - Mickael Istria (Red Hat Inc.) - initial implementation *******************************************************************************/ -package org.eclipse.jface.text.tests; +package org.eclipse.jface.text.tests.codemining; import java.util.concurrent.atomic.AtomicInteger; @@ -41,6 +41,8 @@ import org.eclipse.jface.text.reconciler.MonoReconciler; import org.eclipse.jface.text.source.AnnotationModel; import org.eclipse.jface.text.source.AnnotationPainter; import org.eclipse.jface.text.source.SourceViewer; +import org.eclipse.jface.text.tests.ScreenshotOnFailureRule; +import org.eclipse.jface.text.tests.TextViewerTest; import org.eclipse.jface.text.tests.util.DisplayHelper; public class CodeMiningTest { diff --git a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/DelayedEchoCodeMiningProvider.java b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/DelayedEchoCodeMiningProvider.java index 8dd93c96f48..ac976cda606 100644 --- a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/DelayedEchoCodeMiningProvider.java +++ b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/DelayedEchoCodeMiningProvider.java @@ -11,7 +11,7 @@ * Contributors: * - Mickael Istria (Red Hat Inc.) - initial implementation *******************************************************************************/ -package org.eclipse.jface.text.tests; +package org.eclipse.jface.text.tests.codemining; import java.util.ArrayList; import java.util.List; diff --git a/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/StaticContentLineCodeMining.java b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/StaticContentLineCodeMining.java new file mode 100644 index 00000000000..59ef8f6e6ce --- /dev/null +++ b/org.eclipse.jface.text.tests/src/org/eclipse/jface/text/tests/codemining/StaticContentLineCodeMining.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2019 Red Hat Inc., and others + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * - Mickael Istria (Red Hat Inc.) + */ +package org.eclipse.jface.text.tests.codemining; + +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.codemining.ICodeMiningProvider; +import org.eclipse.jface.text.codemining.LineContentCodeMining; + +public class StaticContentLineCodeMining extends LineContentCodeMining { + + public StaticContentLineCodeMining(int i, char c, ICodeMiningProvider repeatLettersCodeMiningProvider) { + super(new Position(i, 1), repeatLettersCodeMiningProvider); + setLabel(Character.toString(c)); + } + + @Override + public boolean isResolved() { + return true; + } + +} diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/AbstractInlinedAnnotation.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/AbstractInlinedAnnotation.java index 2eeea983c48..464186604e5 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/AbstractInlinedAnnotation.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/AbstractInlinedAnnotation.java @@ -22,8 +22,10 @@ import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.GC; +import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewerExtension5; import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.Region; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.ISourceViewer; @@ -72,14 +74,24 @@ public abstract class AbstractInlinedAnnotation extends Annotation { } /** - * Returns the position where the annotation must be drawn. + * Returns the position where the annotation must be drawn. For {@link ITextViewerExtension5} + * (enabling folding with widget/model projection), this position is the <strong>model</strong> + * position. * - * @return the position where the annotation must be drawn. + * @return the model position where the annotation must be drawn. */ public Position getPosition() { return position; } + final Position computeWidgetPosition() { + if (fViewer instanceof ITextViewerExtension5) { + IRegion region= ((ITextViewerExtension5) fViewer).modelRange2WidgetRange(new Region(position.getOffset(), position.getLength())); + return new Position(region.getOffset(), region.getLength()); + } + return position; + } + /** * Returns the {@link StyledText} widget where the annotation must be drawn. * diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java index 1bf56916bc6..c29c6332f0a 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/InlinedAnnotationDrawingStrategy.java @@ -32,7 +32,7 @@ import org.eclipse.jface.text.source.AnnotationPainter.IDrawingStrategy; class InlinedAnnotationDrawingStrategy implements IDrawingStrategy { @Override - public void draw(Annotation annotation, GC gc, StyledText textWidget, int offset, int length, Color color) { + public void draw(Annotation annotation, GC gc, StyledText textWidget, int widgetoffset, int length, Color color) { if (!(annotation instanceof AbstractInlinedAnnotation)) { return; } @@ -40,7 +40,7 @@ class InlinedAnnotationDrawingStrategy implements IDrawingStrategy { // The annotation is not in visible lines, don't draw it. return; } - draw((AbstractInlinedAnnotation) annotation, gc, textWidget, offset, length, + draw((AbstractInlinedAnnotation) annotation, gc, textWidget, widgetoffset, length, color); } @@ -50,16 +50,16 @@ class InlinedAnnotationDrawingStrategy implements IDrawingStrategy { * @param annotation the annotation to be drawn * @param gc the graphics context, <code>null</code> when in clearing mode * @param textWidget the text widget to draw on - * @param offset the offset of the line + * @param widgetOffset the offset of the line * @param length the length of the line * @param color the color of the line */ - public static void draw(AbstractInlinedAnnotation annotation, GC gc, StyledText textWidget, int offset, int length, + public static void draw(AbstractInlinedAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length, Color color) { if (annotation instanceof LineHeaderAnnotation) { - draw((LineHeaderAnnotation) annotation, gc, textWidget, offset, length, color); + draw((LineHeaderAnnotation) annotation, gc, textWidget, widgetOffset, length, color); } else { - draw((LineContentAnnotation) annotation, gc, textWidget, offset, length, color); + draw((LineContentAnnotation) annotation, gc, textWidget, widgetOffset, length, color); } } @@ -125,16 +125,16 @@ class InlinedAnnotationDrawingStrategy implements IDrawingStrategy { * @param annotation the annotation to be drawn * @param gc the graphics context, <code>null</code> when in clearing mode * @param textWidget the text widget to draw on - * @param offset the offset of the line + * @param widgetOffset the offset of the line in the widget (not model) * @param length the length of the line * @param color the color of the line */ - private static void draw(LineContentAnnotation annotation, GC gc, StyledText textWidget, int offset, int length, + private static void draw(LineContentAnnotation annotation, GC gc, StyledText textWidget, int widgetOffset, int length, Color color) { - if (annotation.drawRightToPreviousChar(offset)) { - drawAsRightOfPreviousCharacter(annotation, gc, textWidget, offset, length, color); + if (annotation.drawRightToPreviousChar(widgetOffset)) { + drawAsRightOfPreviousCharacter(annotation, gc, textWidget, widgetOffset, length, color); } else { - drawAsLeftOf1stCharacter(annotation, gc, textWidget, offset, length, color); + drawAsLeftOf1stCharacter(annotation, gc, textWidget, widgetOffset, length, color); } } diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java index 76c97148b57..332a8a5837b 100644 --- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java +++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/inlined/LineContentAnnotation.java @@ -108,15 +108,15 @@ public class LineContentAnnotation extends AbstractInlinedAnnotation { * @return the style to apply with GlyphMetrics width only if needed.
*/
StyleRange updateStyle(StyleRange style) {
- boolean usePreviousChar= drawRightToPreviousChar(getPosition().getOffset());
+ Position widgetPosition= computeWidgetPosition();
+ boolean usePreviousChar= drawRightToPreviousChar(widgetPosition.getOffset());
if (width == 0 || getRedrawnCharacterWidth() == 0) {
return null;
}
int fullWidth= width + getRedrawnCharacterWidth();
if (style == null) {
style= new StyleRange();
- Position position= getPosition();
- style.start= position.getOffset();
+ style.start= widgetPosition.getOffset();
if (usePreviousChar) {
style.start--;
}
@@ -144,8 +144,8 @@ public class LineContentAnnotation extends AbstractInlinedAnnotation { return style;
}
- boolean drawRightToPreviousChar(int offset) {
- return getTextWidget().getLineAtOffset(offset) == getTextWidget().getLineAtOffset(offset - 1);
+ boolean drawRightToPreviousChar(int widgetOffset) {
+ return getTextWidget().getLineAtOffset(widgetOffset) == getTextWidget().getLineAtOffset(widgetOffset - 1);
}
}
|