Bug 31289

Summary: StringIndexOutOfBoundsException is ASTRewrite
Product: [Eclipse Project] JDT Reporter: Martin Aeschlimann <martinae>
Component: CoreAssignee: Olivier Thomann <Olivier_Thomann>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: akiezun, kai-uwe_maetzel
Version: 2.1   
Target Milestone: 2.1 RC1   
Hardware: PC   
OS: Windows 2000   
Whiteboard:

Description Martin Aeschlimann CLA 2003-02-07 09:25:34 EST
20030206

1. select CUCorrectionProposal.createCompilationUnitChange
 pull up

java.lang.reflect.InvocationTargetException: 
java.lang.StringIndexOutOfBoundsException: String index out of range: 122
	at java.lang.String.substring(String.java(Compiled Code))
	at org.eclipse.jdt.internal.corext.dom.ASTRewriteAnalyzer.doTextInsert
(ASTRewriteAnalyzer.java:681)
	at org.eclipse.jdt.internal.corext.dom.ASTRewriteAnalyzer.rewriteList
(ASTRewriteAnalyzer.java:531)
	at 
org.eclipse.jdt.internal.corext.dom.ASTRewriteAnalyzer.rewriteParagraphList
(ASTRewriteAnalyzer.java:355)
	at org.eclipse.jdt.internal.corext.dom.ASTRewriteAnalyzer.visit
(ASTRewriteAnalyzer.java:887)
	at org.eclipse.jdt.core.dom.TypeDeclaration.accept0
(TypeDeclaration.java:154)
	at org.eclipse.jdt.internal.corext.dom.ASTRewriteAnalyzer.visitList
(ASTRewriteAnalyzer.java(Compiled Code))
	at org.eclipse.jdt.internal.corext.dom.ASTRewriteAnalyzer.visitList
(ASTRewriteAnalyzer.java(Compiled Code))
	at 
org.eclipse.jdt.internal.corext.dom.ASTRewriteAnalyzer.rewriteParagraphList
(ASTRewriteAnalyzer.java:350)
	at org.eclipse.jdt.internal.corext.dom.ASTRewriteAnalyzer.visit
(ASTRewriteAnalyzer.java:806)
	at org.eclipse.jdt.core.dom.CompilationUnit.accept0
(CompilationUnit.java:155)
	at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java(Compiled Code))
	at org.eclipse.jdt.internal.corext.dom.ASTRewrite.rewriteNode
(ASTRewrite.java:120)
	at 
org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoring.fillWith
RewriteEdits(PullUpRefactoring.java:1573)
	at 
org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoring.createCh
angeManager(PullUpRefactoring.java:1171)
	at 
org.eclipse.jdt.internal.corext.refactoring.structure.PullUpRefactoring.checkInp
ut(PullUpRefactoring.java:688)
	at org.eclipse.jdt.internal.ui.refactoring.CheckConditionsOperation.run
(CheckConditionsOperation.java:59)
	at org.eclipse.jdt.internal.ui.refactoring.CreateChangeOperation.run
(CreateChangeOperation.java:94)
	at org.eclipse.jdt.internal.ui.refactoring.PerformChangeOperation.run
(PerformChangeOperation.java:138)
	at org.eclipse.jface.operation.ModalContext.runInCurrentThread
(ModalContext.java:296)
	at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:246)
	at org.eclipse.jface.wizard.WizardDialog.run(WizardDialog.java:716)
	at 
org.eclipse.jdt.internal.ui.refactoring.PerformRefactoringUtil.performRefactorin
g(PerformRefactoringUtil.java:43)
	at 
org.eclipse.jdt.internal.ui.refactoring.RefactoringWizard.performFinish
(RefactoringWizard.java:366)
	at 
org.eclipse.jdt.internal.ui.refactoring.UserInputWizardPage.performFinish
(UserInputWizardPage.java:113)
	at 
org.eclipse.jdt.internal.ui.refactoring.PullUpInputPage2.performFinish
(PullUpInputPage2.java:373)
	at 
org.eclipse.jdt.internal.ui.refactoring.RefactoringWizard.performFinish
(RefactoringWizard.java:429)
	at org.eclipse.jface.wizard.WizardDialog.finishPressed
(WizardDialog.java:570)
	at 
org.eclipse.jdt.internal.ui.refactoring.RefactoringWizardDialog.finishPressed
(RefactoringWizardDialog.java:73)
	at org.eclipse.jface.wizard.WizardDialog.buttonPressed
(WizardDialog.java:308)
	at org.eclipse.jface.dialogs.Dialog$1.widgetSelected(Dialog.java:417)
	at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java
(Compiled Code))
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java
(Compiled Code))
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java
(Compiled Code))
	at org.eclipse.jface.window.Window.runEventLoop(Window.java(Compiled 
Code))
	at org.eclipse.jface.window.Window.open(Window.java:541)
	at 
org.eclipse.jdt.internal.ui.refactoring.actions.RefactoringStarter.activate
(RefactoringStarter.java:59)
	at org.eclipse.jdt.ui.actions.PullUpAction.startRefactoring
(PullUpAction.java:177)
	at org.eclipse.jdt.ui.actions.PullUpAction.run(PullUpAction.java:100)
	at org.eclipse.jdt.ui.actions.SelectionDispatchAction.dispatchRun
(SelectionDispatchAction.java:191)
	at org.eclipse.jdt.ui.actions.SelectionDispatchAction.run
(SelectionDispatchAction.java:169)
	at org.eclipse.jface.action.Action.runWithEvent(Action.java:804)
	at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection
(ActionContributionItem.java:450)
	at 
org.eclipse.jface.action.ActionContributionItem$ActionListener.handleEvent
(ActionContributionItem.java(Compiled Code))
	at 
org.eclipse.jface.action.ActionContributionItem$ActionListener.handleEvent
(ActionContributionItem.java(Compiled Code))
	at 
org.eclipse.jface.action.ActionContributionItem$ActionListener.handleEvent
(ActionContributionItem.java(Compiled Code))
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java
(Compiled Code))
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java
(Compiled Code))
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java
(Compiled Code))
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java
(Compiled Code))
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java
(Compiled Code))
	at org.eclipse.ui.internal.Workbench.run(Workbench.java:1272)
	at org.eclipse.core.internal.boot.InternalBootLoader.run
(InternalBootLoader.java:845)
	at org.eclipse.core.boot.BootLoader.run(BootLoader.java:461)
	at java.lang.reflect.Method.invoke(Native Method)
	at org.eclipse.core.launcher.Main.basicRun(Main.java:247)
	at org.eclipse.core.launcher.Main.run(Main.java:703)
	at org.eclipse.core.launcher.Main.main(Main.java:539)
Comment 1 Martin Aeschlimann CLA 2003-02-07 09:50:23 EST
Bug in the code formatter, positiosn retruned are greater than the length of 
the string.

public void testBug31289() throws Exception {
	// str-len == 100
	String str= "protected X createCompilationUnitChange(int MISSING,int 
MISSING,int MISSING) throws CoreException {}");

	int[] pos=  {10, 10, 40, 50, 52, 62, 64, 74, 98, 99 };

	ICodeFormatter formatter= ToolFactory.createDefaultCodeFormatter(null);
	String formatted= formatter.format(str, 1, pos, "\r\n");
	
	int len= formatted.length();
	
	for (int i= 0; i < pos.length; i++) {
		assertTrue(pos[i] < len);
	}
}

Comment 2 Martin Aeschlimann CLA 2003-02-07 09:53:05 EST
*** Bug 30880 has been marked as a duplicate of this bug. ***
Comment 3 Olivier Thomann CLA 2003-02-07 11:26:54 EST
I tried your test case.
When you format: 
	String str= "protected X createCompilationUnitChange(int MISSING,int 
MISSING,int MISSING) throws CoreException {}");

I end up with:
"protected X createCompilationUnitChange(int MISSING, int MISSING, int MISSING)
	throws CoreException {
}"

which is 106 character long.
The positions are mapped to:
[10, 10, 40, 50, 53, 63, 66, 76, 102, 105]

98 and 99 are the positions of the '{' and '}' in the original source. They are
mapped to 102 and 105 which are the corresponding positions in the formatted source.

So I see no problem. Let me know what are your settings for the formatter. I
might not test the same thing.

Let me know what are the mapped positions you get and the formatted string.
Comment 4 Olivier Thomann CLA 2003-02-07 11:55:13 EST
Without further information, I cannot fix it. What I get looks ok to me.
Comment 5 Martin Aeschlimann CLA 2003-02-07 12:03:28 EST
public class DeclTest extends TestCase {
	public DeclTest(String name) {
		super(name);
	}
	public static Test suite() {
		return new DeclTest("testBug31289");
	}
	public void testBug31289() throws Exception {
		Hashtable options= JavaCore.getDefaultOptions();
		options.put(JavaCore.FORMATTER_TAB_CHAR, JavaCore.SPACE);
		options.put(JavaCore.FORMATTER_TAB_SIZE, "4");
		JavaCore.setOptions(options);				
		
		// str-len == 100
		String str= "protected X createCompilationUnitChange(" +
			"int MISSING,int MISSING,int MISSING) throws" +
			" CoreException {}";
		System.out.println("orig-length: " + str.length());

		int[] pos=  {10, 10, 40, 50, 52, 62, 64, 74, 98, 99 };

		ICodeFormatter formatter= 
			ToolFactory.createDefaultCodeFormatter(null);
		String formatted= formatter.format(str, 1, pos, "\r\n");
	
		int len= formatted.length();
		boolean isTooBig= false;
		System.out.println("length: " + len + "\ncontent:\n" + 
formatted);
		for (int i= 0; i < pos.length; i++) {
			System.out.print(", " + pos[i]);
			isTooBig= isTooBig || (pos[i] < len);
		}
		assertFalse(isTooBig);
	}
}

The output is
orig-length: 100
length: 149
content:
    protected X createCompilationUnitChange(
        int MISSING,
        int MISSING,
        int MISSING)
        throws CoreException {
    }
, 14, 14, 54, 64, 76, 86, 98, 108, 149, 152
Comment 6 Olivier Thomann CLA 2003-02-07 12:37:54 EST
Ok, I reproduced it. I will investigate.
Comment 7 Olivier Thomann CLA 2003-02-07 13:00:19 EST
The bug is located in the mapping of positions during the line splitting. We
know that this doesn't work very well. So you have two solutions:
1) don't try to map positions
2) don't try to split (increase the line split value).

It is clearly to risky to change that code now. This code will disappear anyway
as soon as the new code formatter is ready.
Comment 8 Martin Aeschlimann CLA 2003-02-07 13:43:51 EST
I'm required to get the positions (have to replace certain pieces in the code), 
so I will disable the splitting. 

Kai, you might want to make sure that the editor can add a guard for the wrong 
positions out of range.

fixed > 200302
Comment 9 Olivier Thomann CLA 2003-03-11 11:33:16 EST
Could you please verify this one as you fixed it?
Thanks.