View | Details | Raw Unified | Return to bug 236230 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsMassiveTests.java (-480 / +236 lines)
Lines 15-26 Link Here
15
import java.io.IOException;
15
import java.io.IOException;
16
import java.text.SimpleDateFormat;
16
import java.text.SimpleDateFormat;
17
import java.util.ArrayList;
17
import java.util.ArrayList;
18
import java.util.Arrays;
19
import java.util.Date;
18
import java.util.Date;
20
import java.util.HashMap;
19
import java.util.HashMap;
21
import java.util.List;
20
import java.util.List;
22
import java.util.Map;
21
import java.util.Map;
23
import java.util.StringTokenizer;
24
22
25
import junit.framework.AssertionFailedError;
23
import junit.framework.AssertionFailedError;
26
import junit.framework.ComparisonFailure;
24
import junit.framework.ComparisonFailure;
Lines 30-45 Link Here
30
import org.eclipse.core.runtime.IPath;
28
import org.eclipse.core.runtime.IPath;
31
import org.eclipse.core.runtime.Path;
29
import org.eclipse.core.runtime.Path;
32
import org.eclipse.jdt.core.formatter.CodeFormatter;
30
import org.eclipse.jdt.core.formatter.CodeFormatter;
33
import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
34
import org.eclipse.jdt.core.tests.model.ModelTestsUtil;
31
import org.eclipse.jdt.core.tests.model.ModelTestsUtil;
35
import org.eclipse.jdt.core.tests.util.Util;
32
import org.eclipse.jdt.core.tests.util.Util;
36
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
37
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
38
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
39
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
33
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
40
import org.eclipse.jdt.internal.compiler.parser.Scanner;
41
import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil;
42
import org.eclipse.jdt.internal.core.util.SimpleDocument;
43
import org.eclipse.jdt.internal.formatter.DefaultCodeFormatter;
34
import org.eclipse.jdt.internal.formatter.DefaultCodeFormatter;
44
import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions;
35
import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions;
45
import org.eclipse.text.edits.TextEdit;
36
import org.eclipse.text.edits.TextEdit;
Lines 102-178 Link Here
102
 * <code>linesLeading</code> (e.g. ignore white spaces at the beginning of the
93
 * <code>linesLeading</code> (e.g. ignore white spaces at the beginning of the
103
 * lines, including the star inside javadoc or block comments):
94
 * lines, including the star inside javadoc or block comments):
104
 * <ul>
95
 * <ul>
105
 * 	<li>Eclipse 3.0 performance workspace (9951 units):<ul>
96
 * 	<li>JUnit 3.8.2 workspace (71 units):
97
 * 	<ul>
106
 * 		<li>0 error</li>
98
 * 		<li>0 error</li>
107
 * 		<li>0 failures</li>
99
 * 		<li>0 failures</li>
108
 * 		<li>8 failures due to old formatter</li>
100
 * 		<li>0 failures due to old formatter</li>
109
 * 		<li>723 files have different lines leading spaces</li>
101
 * 		<li>8 files have different lines leading spaces</li>
110
 * 		<li>9 files have different spaces</li>
102
 * 		<li>0 files have different spaces</li>
111
 *		</ul></li>
103
 *		</ul></li>
112
 * 	<li>Eclipse 3.4 workspace (16592 units):<ul>
104
 * 	<li>Eclipse 3.0 performance workspace (9951 units):
105
 * 	<ul>
113
 * 		<li>0 error</li>
106
 * 		<li>0 error</li>
114
 * 		<li>11 failures</li>
107
 * 		<li>1 failures</li>
115
 * 		<li>17 failures due to old formatter</li>
108
 * 		<li>8 failures due to old formatter</li>
116
 * 		<li>1244 files have different lines leading spaces</li>
109
 * 		<li>722 files have different lines leading spaces</li>
117
 * 		<li>11 files have different spaces</li>
110
 * 		<li>9 files have different spaces</li>
118
 *		</ul></li>
111
 *		</ul></li>
119
 *		<li>ganymede M5 workspace (25819 units):<ul>
112
 * 	<li>Eclipse 3.4 workspace (17890 units):
113
 * 	<ul>
120
 * 		<li>0 error</li>
114
 * 		<li>0 error</li>
121
 * 		<li>12 failures due to different output while reformatting!</li>
115
 * 		<li>17 failures</li>
122
 * 		<li>15 failures due to old formatter</li>
116
 * 		<li>21 failures due to old formatter</li>
123
 * 		<li>1371 files have different line leading spaces when reformatting!</li>
117
 * 		<li>1372 files have different lines leading spaces</li>
124
 * 		<li>14 files have different spaces when reformatting!</li>
118
 * 		<li>12 files have different spaces</li>
125
 *		</ul></li>
119
 *		</ul></li>
126
 *		<li>ganymede M6a workspace (26336 units):<ul>
120
 *		<li>ganymede workspace (33190 units):
127
 * 		<li>0 error</li>
121
 *		<ul>
128
 * 		<li>16 failures due to different output while reformatting!</li>
122
 * 		<li>1 error</li>
129
 * 		<li>17 failures due to old formatter</li>
123
 * 		<li>21 failures due to different output while reformatting!</li>
130
 * 		<li>1469 files have different line leading spaces when reformatting!</li>
124
 * 		<li>21 failures due to old formatter</li>
131
 * 		<li>14 files have different spaces when reformatting!</li>
125
 * 		<li>1780 files have different line leading spaces when reformatting!</li>
126
 * 		<li>20 files have different spaces when reformatting!</li>
132
 *		</ul></li>
127
 *		</ul></li>
133
 * </ul>
128
 * </ul>
134
 */
129
 */
135
public class FormatterCommentsMassiveTests extends FormatterRegressionTests {
130
public class FormatterCommentsMassiveTests extends FormatterRegressionTests {
136
131
137
	private static final String LINE_SEPARATOR = org.eclipse.jdt.internal.compiler.util.Util.LINE_SEPARATOR;
138
	final File file;
132
	final File file;
139
	final IPath path;
133
	final IPath path;
140
	List failures = new ArrayList();
141
	List expectedFailures = new ArrayList();
142
	List leadingWhitespacesFailures = new ArrayList();
143
	List whitespacesFailures= new ArrayList();
144
	boolean hasSpaceFailure;
134
	boolean hasSpaceFailure;
145
	private int changedHeaderFooter;
135
	private DefaultCodeFormatterOptions preferences;
146
	private int changedPreTags;
136
	private final static File INPUT_DIR = new File(System.getProperty("inputDir"));
147
	private int changedCodeTags;
137
	private final static File OUTPUT_DIR;
148
	private final static boolean DEBUG_TESTS = "true".equals(System.getProperty("debugTests"));
138
	private final static boolean COMPARE;
149
	private final static String DIR = System.getProperty("dir"); //$NON-NLS-1$
150
	private final static String COMPARE = System.getProperty("compare"); //$NON-NLS-1$
151
	private final static int IGNORE_SPACES;
152
	private final static int ALL_SPACES = 1;	// ignore all spaces
153
	private final static int LINES_LEADING_SPACES = 2;	// ignore all spaces at the beginning of all lines
154
	private final static int ALL_COMMENTS_SPACES = 3;	// ignore all spaces inside all comments
155
	private final static int ALL_COMMENTS_LINES_LEADING_SPACES = 4;	// ignore all spaces at the beginning of all comments lines
156
	static {
139
	static {
157
		String ignoreSpaces = System.getProperty("ignoreSpaces"); //$NON-NLS-1$
140
		String dir = System.getProperty("outputDir"); //$NON-NLS-1$
158
		int filterValue;
141
		File outputDir = null;
159
		if ("all".equals(ignoreSpaces)) {
142
		boolean compare = true;
160
			filterValue = ALL_SPACES;
143
		if (dir != null) {
161
		} else if ("linesLeading".equals(ignoreSpaces)) {
144
			outputDir = new File(dir);
162
			filterValue = LINES_LEADING_SPACES;
145
			if (!outputDir.exists()) {
163
		} else if ("comments".equals(ignoreSpaces)) {
146
				compare = false;
164
			filterValue = ALL_COMMENTS_SPACES;
147
				System.err.println("WARNING: The output directory "+dir+" does not exist...");
165
		} else if ("commentsLinesLeading".equals(ignoreSpaces)) {
148
				System.err.println("=> NO comparison will be done! The formatted files will be written there instead.");
166
			filterValue = ALL_COMMENTS_LINES_LEADING_SPACES;
149
				try {
167
		} else {
150
	                Thread.sleep(1000);
168
			filterValue = 0; // no filter
151
                } catch (InterruptedException e) {
152
	                // skip
153
                }
154
			}
169
		}
155
		}
170
		IGNORE_SPACES = filterValue;
156
		OUTPUT_DIR = outputDir;
157
		COMPARE = compare;
171
	}
158
	}
172
	private final static int FORMAT_REPEAT  = Integer.parseInt(System.getProperty("repeat", "2")); //$NON-NLS-1$
159
	private final static int FORMAT_REPEAT  = Integer.parseInt(System.getProperty("repeat", "2")); //$NON-NLS-1$
160
	
161
	// Failures management
162
	final static int NO_OUTPUT_FAILURE = 0;
163
	final static int COMPARISON_FAILURE = 1;
164
	final static int REFORMATTING_FAILURE = 2;
165
	final static int REFORMATTING_LEADING_FAILURE = 4;
166
	final static int REFORMATTING_WHITESPACES_FAILURE = 5;
167
	final static int REFORMATTING_EXPECTED_FAILURE = 3;
168
	class FormattingFailure {
169
		String action;
170
		List failures = new ArrayList();
171
		public FormattingFailure() {
172
        }
173
		public FormattingFailure(String action) {
174
	        this.action = action;
175
        }
176
		public String toString() {
177
			if (action == null) {
178
				return "no output while formatting";
179
			}
180
	        return "different output while "+action;
181
        }
182
		
183
	}
184
	final static FormattingFailure[] FAILURES = new FormattingFailure[6];
185
	{
186
		FAILURES[NO_OUTPUT_FAILURE] = new FormattingFailure();
187
		FAILURES[COMPARISON_FAILURE] = new FormattingFailure("comparing with previous version");
188
		FAILURES[REFORMATTING_FAILURE] = new FormattingFailure("reformatting twice");
189
		FAILURES[REFORMATTING_LEADING_FAILURE] = new FormattingFailure("reformatting twice but only by leading whitespaces");
190
		FAILURES[REFORMATTING_WHITESPACES_FAILURE] = new FormattingFailure("reformatting twice but only by whitespaces");
191
		FAILURES[REFORMATTING_EXPECTED_FAILURE] = new FormattingFailure("reformatting twice but was expected");
192
	}
173
	private static final int MAX_FAILURES = Integer.parseInt(System.getProperty("maxFailures", "100")); // Max failures using string comparison
193
	private static final int MAX_FAILURES = Integer.parseInt(System.getProperty("maxFailures", "100")); // Max failures using string comparison
174
	private static boolean ASSERT_EQUALS_STRINGS = MAX_FAILURES > 0;
194
	private static boolean ASSERT_EQUALS_STRINGS = MAX_FAILURES > 0;
175
	private final static IPath[] EXPECTED_FAILURES = DIR.indexOf("v34") < 0
195
	private final static IPath[] EXPECTED_FAILURES = INPUT_DIR.getPath().indexOf("v34") < 0
176
		? new IPath[] {
196
		? new IPath[] {
177
			new Path("org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java"),
197
			new Path("org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java"),
178
			new Path("org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java"),
198
			new Path("org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java"),
Lines 184-189 Link Here
184
			new Path("org/eclipse/team/internal/ccvs/ui/wizards/UpdateWizard.java"),
204
			new Path("org/eclipse/team/internal/ccvs/ui/wizards/UpdateWizard.java"),
185
		}
205
		}
186
		:	new IPath[] {
206
		:	new IPath[] {
207
			// Eclipse
187
			new Path("org/eclipse/equinox/internal/p2/director/NewDependencyExpander.java"),
208
			new Path("org/eclipse/equinox/internal/p2/director/NewDependencyExpander.java"),
188
			new Path("org/eclipse/jdt/core/JavaCore.java"),
209
			new Path("org/eclipse/jdt/core/JavaCore.java"),
189
			new Path("org/eclipse/jdt/internal/codeassist/CompletionEngine.java"),
210
			new Path("org/eclipse/jdt/internal/codeassist/CompletionEngine.java"),
Lines 203-223 Link Here
203
			new Path("org/eclipse/jdt/internal/core/search/JavaSearchScope.java"),
224
			new Path("org/eclipse/jdt/internal/core/search/JavaSearchScope.java"),
204
			new Path("org/eclipse/jdt/internal/eval/EvaluationContext.java"),
225
			new Path("org/eclipse/jdt/internal/eval/EvaluationContext.java"),
205
			new Path("org/eclipse/jdt/internal/ui/text/javadoc/JavadocContentAccess2.java"),
226
			new Path("org/eclipse/jdt/internal/ui/text/javadoc/JavadocContentAccess2.java"),
227
			new Path("org/eclipse/jdt/internal/apt/pluggable/core/filer/IdeJavaSourceOutputStream.java"),
206
			new Path("org/eclipse/team/internal/ccvs/ui/mappings/WorkspaceSubscriberContext.java"),
228
			new Path("org/eclipse/team/internal/ccvs/ui/mappings/WorkspaceSubscriberContext.java"),
229
			// Ganymede
230
			new Path("com/ibm/icu/text/Collator.java"),
231
			new Path("org/apache/lucene/analysis/ISOLatin1AccentFilter.java"),
207
	};
232
	};
208
	static {
209
		// Sort expected failures to allow binary search
210
		Arrays.sort(EXPECTED_FAILURES);
211
	}
212
	
233
	
213
public static Test suite() {
234
public static Test suite() {
214
	TestSuite suite = new Suite(FormatterCommentsMassiveTests.class.getName());
235
	TestSuite suite = new Suite(FormatterCommentsMassiveTests.class.getName());
215
	try {
236
	try {
216
		File testDir = ModelTestsUtil.getWorkspaceRoot().getLocation().toFile();
217
		if (DIR != null) {
218
			File dir = new File(DIR);
219
			if (dir.exists()) testDir = dir;
220
		}
221
		FileFilter filter = new FileFilter() {
237
		FileFilter filter = new FileFilter() {
222
			public boolean accept(File pathname) {
238
			public boolean accept(File pathname) {
223
	            return pathname.isDirectory() || pathname.getPath().endsWith(".java");
239
	            return pathname.isDirectory() || pathname.getPath().endsWith(".java");
Lines 227-240 Link Here
227
		SimpleDateFormat format = new SimpleDateFormat();
243
		SimpleDateFormat format = new SimpleDateFormat();
228
		Date now = new Date(start);
244
		Date now = new Date(start);
229
		System.out.println("Date of test: "+format.format(now));
245
		System.out.println("Date of test: "+format.format(now));
230
		System.out.print("Get all Java files located in "+testDir+"...");
246
		System.out.print("Get all Java files located in "+INPUT_DIR+"...");
231
		File[] allFiles = ModelTestsUtil.getAllFiles(testDir, filter);
247
		File[] allFiles = ModelTestsUtil.getAllFiles(INPUT_DIR, filter);
232
		int length = allFiles.length;
248
		int length = allFiles.length;
233
		System.out.println(length+" found in " + (System.currentTimeMillis() - start) + "ms");
249
		System.out.println(length+" found in " + (System.currentTimeMillis() - start) + "ms");
234
		for (int i=0; i<length; i++) {
250
		for (int i=0; i<length; i++) {
235
			suite.addTest(new FormatterCommentsMassiveTests(allFiles[i]));
251
			suite.addTest(new FormatterCommentsMassiveTests(allFiles[i]));
236
		}
252
		}
237
//		ASSERT_EQUALS_STRINGS = length < 15000; 
238
    } catch (Exception e) {
253
    } catch (Exception e) {
239
    	// skip
254
    	// skip
240
    }
255
    }
Lines 244-250 Link Here
244
public FormatterCommentsMassiveTests(File file) {
259
public FormatterCommentsMassiveTests(File file) {
245
	super("testCompare");
260
	super("testCompare");
246
	this.file = file;
261
	this.file = file;
247
	this.path = new Path(file.getPath().substring(DIR.length()+1));
262
	this.path = new Path(file.getPath().substring(INPUT_DIR.getPath().length()+1));
248
}
263
}
249
264
250
/* (non-Javadoc)
265
/* (non-Javadoc)
Lines 260-265 Link Here
260
public void setUp() throws Exception {
275
public void setUp() throws Exception {
261
	super.setUp();
276
	super.setUp();
262
	this.hasSpaceFailure = false;
277
	this.hasSpaceFailure = false;
278
	this.preferences = DefaultCodeFormatterOptions.getEclipseDefaultSettings();
263
}
279
}
264
280
265
/* (non-Javadoc)
281
/* (non-Javadoc)
Lines 280-335 Link Here
280
 * @see org.eclipse.jdt.core.tests.formatter.FormatterRegressionTests#tearDownSuite()
296
 * @see org.eclipse.jdt.core.tests.formatter.FormatterRegressionTests#tearDownSuite()
281
 */
297
 */
282
public void tearDownSuite() throws Exception {
298
public void tearDownSuite() throws Exception {
283
	// skip standard model suite tear down
299
	if (OUTPUT_DIR != null) {
284
	int sFailures = this.failures.size();
300
		if (COMPARE) {
285
	int seFailures = this.expectedFailures.size();
301
			System.out.println("Comparison done with output files located in "+OUTPUT_DIR);
286
	int swFailures = this.whitespacesFailures.size();
287
	int slwFailures = this.leadingWhitespacesFailures.size();
288
	String failuresType = COMPARE != null ? "than old formatter" : "when reformatting";
289
	System.out.println();
290
	if (sFailures > 0) {
291
		System.out.println(sFailures+" files has still different output while reformatting!");
292
	}
293
	if (seFailures > 0) {
294
		System.out.println(seFailures+" files has still different output while reformatting due to old formatter bugs!");
295
	}
296
	if (slwFailures == 0) {
297
		System.out.println("No file has different line leading spaces "+failuresType+" :-)");
298
	} else {
299
		System.out.println(slwFailures+" files have different line leading spaces "+failuresType+"!");
300
	}
301
	if (swFailures > 0) {
302
		System.out.println(swFailures+" files have different spaces "+failuresType+"!");
303
	}
304
	if (this.changedHeaderFooter >0) {
305
		System.out.println(this.changedHeaderFooter+" differences in header/footer have been found");
306
	}
307
	if (this.changedPreTags >0) {
308
		System.out.println(this.changedPreTags+" differences in <pre> tags (blank lines) have been found");
309
	}
310
	System.out.println();
311
	if (sFailures > 0) {
312
		System.out.println("List of files with different output "+failuresType+":");
313
		for (int i=0; i<sFailures; i++) {
314
			System.out.println("	- "+this.failures.get(i));
315
		}
302
		}
316
	}
303
	}
317
	if (seFailures > 0) {
304
	// skip standard model suite tear down
318
		System.out.println("List of files with different output "+failuresType+" (due to old formatter bugs):");
305
	System.out.println();
319
		for (int i=0; i<seFailures; i++) {
306
	int max = FAILURES.length;
320
			System.out.println("	- "+this.expectedFailures.get(i));
307
	for (int i=0; i<max; i++) {
321
		}
308
		List failures = FAILURES[i].failures;
322
	}
309
		int size = failures.size();
323
	if (slwFailures > 0) {
310
		if (size > 0) {
324
		System.out.println("List of files with different line leading spaces "+failuresType+":");
311
			System.out.print(size);
325
		for (int i=0; i<slwFailures; i++) {
312
			System.out.print(" file");
326
			System.out.println("	- "+this.leadingWhitespacesFailures.get(i));
313
			if (size == 1) {
314
				System.out.print(" has ");
315
			} else {
316
				System.out.print("s have ");
317
			}
318
			System.out.print(FAILURES[i]);
319
			System.out.println('!');
327
		}
320
		}
328
	}
321
	}
329
	if (swFailures > 0) {
322
	System.out.println();
330
		System.out.println("List of files with different spaces "+failuresType+":");
323
	for (int i=0; i<max; i++) {
331
		for (int i=0; i<swFailures; i++) {
324
		List failures = FAILURES[i].failures;
332
			System.out.println("	- "+this.whitespacesFailures.get(i));
325
		int size = failures.size();
326
		if (size > 0) {
327
			System.out.println("List of file(s) with "+FAILURES[i]+":");
328
			for (int j=0; j<size; j++) {
329
				System.out.println("	- "+failures.get(j));
330
			}
333
		}
331
		}
334
	}
332
	}
335
}
333
}
Lines 340-542 Link Here
340
 * The line separators in 'actual' are converted to '\n' before the comparison.
338
 * The line separators in 'actual' are converted to '\n' before the comparison.
341
 */
339
 */
342
protected void assertSourceEquals(String message, String expected, String actual) {
340
protected void assertSourceEquals(String message, String expected, String actual) {
341
	if (expected == null) {
342
		assertNull(message, actual);
343
		return;
344
	}
343
	if (actual == null) {
345
	if (actual == null) {
344
		assertEquals(message, expected, null);
346
		assertEquals(message, expected, null);
345
		return;
347
		return;
346
	}
348
	}
349
	expected = Util.convertToIndependantLineDelimiter(expected);
347
	actual = Util.convertToIndependantLineDelimiter(actual);
350
	actual = Util.convertToIndependantLineDelimiter(actual);
348
	try {
351
	if (ASSERT_EQUALS_STRINGS) {
349
		if (ASSERT_EQUALS_STRINGS) {
352
		assertEquals(message, expected, actual);
350
			assertEquals(message, expected, actual);
353
	} else {
351
		} else {
354
		assertTrue(message, actual.equals(expected));
352
			assertTrue(message, actual.equals(expected));
353
		}
354
	}
355
	catch (ComparisonFailure cf) {
356
		if ("true".equals(COMPARE)) {
357
			String trimmedExpected = expected;
358
			String trimmedActual = actual;
359
			switch (IGNORE_SPACES) {
360
				case ALL_SPACES:
361
					trimmedExpected = ModelTestsUtil.removeWhiteSpace(expected);
362
					trimmedActual= ModelTestsUtil.removeWhiteSpace(actual);
363
					if (trimmedExpected.equals(trimmedActual)) {
364
						this.whitespacesFailures.add(this.path);
365
						return;
366
					}
367
					break;
368
				case LINES_LEADING_SPACES:
369
					trimmedExpected = ModelTestsUtil.trimLinesLeadingWhitespaces(expected);
370
					trimmedActual= ModelTestsUtil.trimLinesLeadingWhitespaces(actual);
371
					if (trimmedExpected.equals(trimmedActual)) {
372
						this.leadingWhitespacesFailures.add(this.path);
373
						return;
374
					}
375
					trimmedExpected = ModelTestsUtil.removeWhiteSpace(expected);
376
					trimmedActual= ModelTestsUtil.removeWhiteSpace(actual);
377
					if (trimmedExpected.equals(trimmedActual)) {
378
						this.whitespacesFailures.add(this.path);
379
						return;
380
					}
381
					break;
382
			}
383
			if (DEBUG_TESTS && ASSERT_EQUALS_STRINGS) {
384
				assertEquals(message, trimmedExpected, trimmedActual);
385
			}
386
		}
387
		this.failures.add(this.path);
388
		ASSERT_EQUALS_STRINGS = this.failures.size() < MAX_FAILURES;
389
		throw cf;
390
	}
391
	catch (AssertionFailedError afe) {
392
		this.failures.add(this.path);
393
		throw afe;
394
	}
395
}
396
397
private String cleanAllKnownDifferences(String comment) {
398
	int kind = comment.charAt(1) == '/' ? 1 : comment.charAt(2) == '*' ? 3 : 2;
399
	String cleanedComment = comment;
400
	switch (kind) {
401
		case 1: // line comment
402
			cleanedComment = cleanBlankLinesAfterLineComment(comment);
403
			break;
404
		case 3: // javadoc comment
405
			cleanedComment = cleanHeaderAndFooter(comment);
406
			String newComment = cleanPreTags(cleanedComment);
407
			if (cleanedComment == newComment) {
408
				cleanedComment = cleanCodeTags(cleanedComment);
409
			} else {
410
				cleanedComment = newComment;
411
			}
412
			break;
413
	}
414
	return cleanedComment;
415
}
416
private String cleanHeaderAndFooter(String comment) {
417
	int start = 1; // skip starting '/'
418
	int length = comment.length();
419
	int end = length - 1; // skip ending '/'
420
	while (comment.charAt(start) == '*') {
421
		// remove all contiguous '*' in header
422
		start++;
423
	}
424
	while (comment.charAt(--end) == '*') {
425
		// remove all contiguous '*' in header
426
	}
427
	if (start > 3 || end < (length - 2)) {
428
		this.changedHeaderFooter++;
429
		return comment.substring(start, end);
430
	}
431
	return comment;
432
}
433
434
private String cleanBlankLinesAfterLineComment(String comment) {
435
	int length = comment.length();
436
	if (comment.charAt(length-1) == '\n') {
437
		length--;
438
		if (comment.charAt(length-1) == '\r') {
439
			length--;
440
		}
441
		return comment.substring(0, length);
442
	}
443
	return comment;
444
}
445
446
private String cleanCodeTags(String comment) {
447
	if (comment.indexOf("<code>") < 0) return comment;
448
	StringTokenizer tokenizer = new StringTokenizer(comment, "\r\n\f");
449
	StringBuffer buffer = new StringBuffer();
450
	while (tokenizer.hasMoreTokens()) {
451
		String line = tokenizer.nextToken();
452
		if (line.indexOf("<pre>") >= 0) {
453
			while (line.indexOf("</pre>") < 0) {
454
				line = tokenizer.nextToken();
455
			}
456
		} else {
457
			buffer.append(line);
458
			buffer.append("\n");
459
		}
460
	}
461
	this.changedCodeTags++;
462
	return buffer.toString();
463
}
464
465
private String cleanPreTags(String comment) {
466
	if (comment.indexOf("<pre>") < 0) return comment;
467
	StringTokenizer tokenizer = new StringTokenizer(comment, "\r\n\f");
468
	StringBuffer buffer = new StringBuffer();
469
	StringBuffer emptyLines = new StringBuffer();
470
	String previousLine = null;
471
	while (tokenizer.hasMoreTokens()) {
472
		String line = tokenizer.nextToken();
473
		if (line.trim() == "*") {
474
			if (previousLine == null || previousLine.indexOf("<pre>") < 0) {
475
				buffer.append(line);
476
				buffer.append("\n");
477
				continue;
478
			} else {
479
				emptyLines.append(line);
480
				emptyLines.append("\n");
481
			}
482
		} else if (line.indexOf("<code>") >= 0) {
483
			while (line.indexOf("</code>") < 0) {
484
				line = tokenizer.nextToken();
485
			}
486
		} else if (emptyLines.length() != 0) {
487
			if (line.indexOf("</pre>") < 0) {
488
				buffer.append(emptyLines);
489
				emptyLines.setLength(0);
490
			}
491
			buffer.append(line);
492
			buffer.append("\n");
493
		} else {
494
			buffer.append(line);
495
			buffer.append("\n");
496
		}
497
		previousLine = line;
498
	}
355
	}
499
	this.changedPreTags++;
500
	return buffer.toString();
501
}
356
}
502
357
503
DefaultCodeFormatter codeFormatter() {
358
DefaultCodeFormatter codeFormatter() {
504
	DefaultCodeFormatterOptions preferences = DefaultCodeFormatterOptions.getEclipseDefaultSettings();
359
	DefaultCodeFormatter codeFormatter = new DefaultCodeFormatter(this.preferences, getDefaultCompilerOptions());
505
	DefaultCodeFormatter codeFormatter = new DefaultCodeFormatter(preferences);
506
	return codeFormatter;
360
	return codeFormatter;
507
}
361
}
508
362
509
void compareFormattedSource() throws IOException, Exception {
363
void compareFormattedSource() throws IOException, Exception {
510
	DefaultCodeFormatter codeFormatter = codeFormatter();
511
	String source = new String(org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(this.file, null));
364
	String source = new String(org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(this.file, null));
512
	try {
365
	try {
513
		if ("comments".equals(COMPARE)) {
366
		// Format the source
514
			String[] oldFormattedComments = formattedComments(source, true);
367
		String actualResult = runFormatter(codeFormatter(), source, CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.F_INCLUDE_COMMENTS, 0, 0, source.length(), null);
515
			String[] newFormattedComments = formattedComments(source, false);
368
516
			int length = oldFormattedComments == null ? 0 : oldFormattedComments.length;
369
		// Look for output to compare with
517
			this.abortOnFailure = false;
370
		File outputFile = new Path(OUTPUT_DIR.getPath()).append(this.path).toFile();
518
			assertEquals("Unexpected number of comments!", length, newFormattedComments == null ? 0 : newFormattedComments.length);
371
		if (COMPARE) {
519
			for (int i=0; i<length; i++) {
372
			String expectedResult = new String(org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(outputFile, null));
520
				String oldComment = oldFormattedComments[i];
373
			try {
521
				String newComment = newFormattedComments[i];
374
				assertSourceEquals("Unexpected format output!", expectedResult, actualResult);
522
				if (oldComment == null) {
375
			}
523
					assertNull("Unexpected non-null new comment", newComment);
376
			catch (ComparisonFailure cf) {
524
				} else {
377
				FAILURES[COMPARISON_FAILURE].failures.add(this.path);
525
					String expected = cleanAllKnownDifferences(oldComment);
378
				throw cf;
526
					String actual = cleanAllKnownDifferences(newComment);
379
			}
527
					if (!expected.equals(actual)) {
380
			catch (AssertionFailedError afe) {
528
						String actualResult = runFormatter(codeFormatter, source, CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.F_INCLUDE_COMMENTS, 0, 0, source.length(), null);
381
				FAILURES[COMPARISON_FAILURE].failures.add(this.path);
529
						String expectedResult = expectedFormattedSource(source);
382
				throw afe;
530
						assertEquals("Unexpected difference with formatted comment "+(i+1), Util.convertToIndependantLineDelimiter(expectedResult), Util.convertToIndependantLineDelimiter(actualResult));
531
					}
532
				}
533
			}
383
			}
534
		} else {
384
		} else {
535
			String actualResult = runFormatter(codeFormatter, source, CodeFormatter.K_COMPILATION_UNIT | CodeFormatter.F_INCLUDE_COMMENTS, 0, 0, source.length(), null);
385
			outputFile.getParentFile().mkdirs();
536
			if (!this.hasSpaceFailure && "true".equals(COMPARE)) {
386
			Util.writeToFile(actualResult, outputFile.getAbsolutePath());
537
				String expectedResult = expectedFormattedSource(source);
538
				assertLineEquals(actualResult, source, expectedResult, false);
539
			}
540
		}
387
		}
541
	}
388
	}
542
	catch (Exception e) {
389
	catch (Exception e) {
Lines 566-707 Link Here
566
	return buffer.toString();
413
	return buffer.toString();
567
}
414
}
568
415
569
private String expectedFormattedSource(String source) {
570
	boolean enableNewCommentFormatter = DefaultCodeFormatter.ENABLE_NEW_COMMENTS_FORMAT;
571
	try {
572
		DefaultCodeFormatter.ENABLE_NEW_COMMENTS_FORMAT = false;
573
		DefaultCodeFormatter codeFormatter = codeFormatter();
574
		Scanner scanner = new Scanner(true, true, false/*nls*/, ClassFileConstants.JDK1_4/*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
575
		CodeSnippetParsingUtil codeSnippetParsingUtil = new CodeSnippetParsingUtil();
576
		CompilationUnitDeclaration compilationUnitDeclaration = codeSnippetParsingUtil.parseCompilationUnit(source.toCharArray(), getDefaultCompilerOptions(), true);
577
		final TypeDeclaration[] types = compilationUnitDeclaration.types;
578
		int headerEndPosition = types == null ? compilationUnitDeclaration.sourceEnd : types[0].declarationSourceStart;
579
		scanner.setSource(source.toCharArray());
580
		scanner.lineEnds = codeSnippetParsingUtil.recordedParsingInformation.lineEnds;
581
		int[][] commentsPositions = compilationUnitDeclaration.comments;
582
		int length = commentsPositions == null ? 0 : commentsPositions.length;
583
		String[] formattedComments = new String[length];
584
		for (int i=0; i<length; i++) {
585
			int[] positions = commentsPositions[i];
586
			int commentKind = CodeFormatter.K_JAVA_DOC;
587
			int commentStart = positions [0];
588
			int commentEnd = positions [1];
589
			if (commentEnd < 0) { // line or block comments have negative end position
590
				commentEnd = -commentEnd;
591
				if (commentStart > 0) { // block comments have positive start position
592
					commentKind = CodeFormatter.K_MULTI_LINE_COMMENT;
593
				} else {
594
					commentStart = -commentStart;
595
					commentKind = CodeFormatter.K_SINGLE_LINE_COMMENT;
596
				}
597
			}
598
			if (commentStart >= headerEndPosition) {
599
				int indentationLevel = getIndentationLevel(scanner, commentStart);
600
				formattedComments[i] = runFormatter(codeFormatter, source.substring(commentStart, commentEnd), commentKind, indentationLevel, 0, commentEnd - commentStart, LINE_SEPARATOR);
601
			}
602
		}
603
		SimpleDocument document = new SimpleDocument(source);
604
		for (int i=length-1; i>=0; i--) {
605
			if (formattedComments[i] != null) {
606
				int[] positions = commentsPositions[i];
607
				int commentStart = positions [0];
608
				int commentEnd = positions [1];
609
				if (commentEnd < 0) { // line or block comments have negative end position
610
					commentEnd = -commentEnd;
611
					if (commentStart < 0) { // line comments have negative start position
612
						commentStart = -commentStart;
613
					}
614
				}
615
				document.replace(commentStart, commentEnd - commentStart, formattedComments[i]);
616
			}
617
		}
618
		String newSource = document.get();
619
		String oldResult = runFormatter(codeFormatter, newSource, CodeFormatter.K_COMPILATION_UNIT, 0, 0, newSource.length(), null);
620
		return oldResult == null ? newSource : oldResult;
621
	}
622
	finally {
623
		DefaultCodeFormatter.ENABLE_NEW_COMMENTS_FORMAT = enableNewCommentFormatter;
624
	}
625
}
626
private String[] formattedComments(String source, boolean old) {
627
	boolean enableNewCommentFormatter = DefaultCodeFormatter.ENABLE_NEW_COMMENTS_FORMAT;
628
	try {
629
		DefaultCodeFormatter.ENABLE_NEW_COMMENTS_FORMAT = !old;
630
		DefaultCodeFormatter codeFormatter = codeFormatter();
631
		Scanner scanner = new Scanner(true, true, false/*nls*/, ClassFileConstants.JDK1_4/*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
632
		CodeSnippetParsingUtil codeSnippetParsingUtil = new CodeSnippetParsingUtil();
633
		CompilationUnitDeclaration compilationUnitDeclaration = codeSnippetParsingUtil.parseCompilationUnit(source.toCharArray(), getDefaultCompilerOptions(), true);
634
		final TypeDeclaration[] types = compilationUnitDeclaration.types;
635
		int headerEndPosition = types == null ? compilationUnitDeclaration.sourceEnd : types[0].declarationSourceStart;
636
		scanner.setSource(source.toCharArray());
637
		scanner.lineEnds = codeSnippetParsingUtil.recordedParsingInformation.lineEnds;
638
		int[][] commentsPositions = compilationUnitDeclaration.comments;
639
		int length = commentsPositions == null ? 0 : commentsPositions.length;
640
		String[] formattedComments = new String[length];
641
		for (int i=0; i<length; i++) {
642
			int[] positions = commentsPositions[i];
643
			int commentKind = CodeFormatter.K_JAVA_DOC;
644
			int commentStart = positions [0];
645
			int commentEnd = positions [1];
646
			if (commentEnd < 0) { // line or block comments have negative end position
647
				commentEnd = -commentEnd;
648
				if (commentStart > 0) { // block comments have positive start position
649
					commentKind = CodeFormatter.K_MULTI_LINE_COMMENT;
650
				} else {
651
					commentStart = -commentStart;
652
					commentKind = CodeFormatter.K_SINGLE_LINE_COMMENT;
653
				}
654
			}
655
			if (commentStart >= headerEndPosition) {
656
				int indentationLevel = getIndentationLevel(scanner, commentStart);
657
				formattedComments[i] = runFormatter(codeFormatter, source.substring(commentStart, commentEnd), commentKind, indentationLevel, 0, commentEnd - commentStart, LINE_SEPARATOR);
658
			}
659
		}
660
		return formattedComments;
661
	}
662
	finally {
663
		DefaultCodeFormatter.ENABLE_NEW_COMMENTS_FORMAT = enableNewCommentFormatter;
664
	}
665
}
666
667
private int getIndentationLevel(Scanner scanner, int position) {
668
	int indentationLevel = 0;
669
	int numberOfIndentations = 0;
670
	int indentationSize;
671
	try {
672
		indentationSize = Integer.parseInt(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE);
673
	} catch (NumberFormatException nfe) {
674
		indentationSize = 4;
675
	}
676
	int lineNumber = scanner.getLineNumber(position);
677
	int lineStart = scanner.getLineStart(lineNumber);
678
	scanner.resetTo(lineStart, position-1);
679
	while (!scanner.atEnd()) {
680
		int ch = scanner.getNextChar();
681
		switch (ch) {
682
			case '\n':
683
				indentationLevel = 0;
684
				numberOfIndentations = 0;
685
				break;
686
			case '\t':
687
				numberOfIndentations++;
688
				indentationLevel = numberOfIndentations * indentationSize;
689
				break;
690
			default:
691
				indentationLevel++;
692
				if ((indentationLevel%indentationSize) == 0) {
693
					numberOfIndentations++;
694
				}
695
				break;
696
		}
697
	}
698
	if ((indentationLevel%indentationSize) != 0) {
699
		numberOfIndentations++;
700
		indentationLevel = numberOfIndentations * indentationSize;
701
	}
702
	return numberOfIndentations;
703
}
704
705
private Map getDefaultCompilerOptions() {
416
private Map getDefaultCompilerOptions() {
706
	Map optionsMap = new HashMap(30);
417
	Map optionsMap = new HashMap(30);
707
	optionsMap.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.DO_NOT_GENERATE); 
418
	optionsMap.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.DO_NOT_GENERATE); 
Lines 751-758 Link Here
751
	optionsMap.put(CompilerOptions.OPTION_ReportUnusedDeclaredThrownException, CompilerOptions.IGNORE);
462
	optionsMap.put(CompilerOptions.OPTION_ReportUnusedDeclaredThrownException, CompilerOptions.IGNORE);
752
	optionsMap.put(CompilerOptions.OPTION_ReportUnusedDeclaredThrownExceptionWhenOverriding, CompilerOptions.DISABLED); 
463
	optionsMap.put(CompilerOptions.OPTION_ReportUnusedDeclaredThrownExceptionWhenOverriding, CompilerOptions.DISABLED); 
753
	optionsMap.put(CompilerOptions.OPTION_ReportUnqualifiedFieldAccess, CompilerOptions.IGNORE);
464
	optionsMap.put(CompilerOptions.OPTION_ReportUnqualifiedFieldAccess, CompilerOptions.IGNORE);
754
	optionsMap.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4);
465
	optionsMap.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_6);
755
	optionsMap.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2); 
466
	optionsMap.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6); 
756
	optionsMap.put(CompilerOptions.OPTION_TaskTags, ""); //$NON-NLS-1$
467
	optionsMap.put(CompilerOptions.OPTION_TaskTags, ""); //$NON-NLS-1$
757
	optionsMap.put(CompilerOptions.OPTION_TaskPriorities, ""); //$NON-NLS-1$
468
	optionsMap.put(CompilerOptions.OPTION_TaskPriorities, ""); //$NON-NLS-1$
758
	optionsMap.put(CompilerOptions.OPTION_TaskCaseSensitive, CompilerOptions.DISABLED);
469
	optionsMap.put(CompilerOptions.OPTION_TaskCaseSensitive, CompilerOptions.DISABLED);
Lines 761-767 Link Here
761
	optionsMap.put(CompilerOptions.OPTION_ReportSpecialParameterHidingField, CompilerOptions.DISABLED); 
472
	optionsMap.put(CompilerOptions.OPTION_ReportSpecialParameterHidingField, CompilerOptions.DISABLED); 
762
	optionsMap.put(CompilerOptions.OPTION_MaxProblemPerUnit, String.valueOf(100));
473
	optionsMap.put(CompilerOptions.OPTION_MaxProblemPerUnit, String.valueOf(100));
763
	optionsMap.put(CompilerOptions.OPTION_InlineJsr, CompilerOptions.DISABLED); 
474
	optionsMap.put(CompilerOptions.OPTION_InlineJsr, CompilerOptions.DISABLED); 
764
	optionsMap.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_5);
475
	optionsMap.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_6);
765
	return optionsMap;
476
	return optionsMap;
766
}
477
}
767
478
Lines 769-830 Link Here
769
	int length = EXPECTED_FAILURES.length;
480
	int length = EXPECTED_FAILURES.length;
770
	for (int i=0; i<length; i++) {
481
	for (int i=0; i<length; i++) {
771
		IPath expectedFailure= EXPECTED_FAILURES[i];
482
		IPath expectedFailure= EXPECTED_FAILURES[i];
772
		if (this.path.matchingFirstSegments(expectedFailure) == expectedFailure.segmentCount()) {
483
		if (this.path.toString().indexOf(expectedFailure.toString()) >= 0) {
773
			this.expectedFailures.add(this.path);
484
			FAILURES[REFORMATTING_EXPECTED_FAILURE].failures.add(this.path);
774
			return true;
485
			return true;
775
		}
486
		}
776
	}
487
	}
777
	return false;
488
	return false;
778
}
489
}
779
490
491
/*
492
private boolean runFormatterWithoutComments(CodeFormatter codeFormatter, String source, int kind, int indentationLevel, int offset, int length, String lineSeparator) {
493
	DefaultCodeFormatterOptions preferencesWithoutComment = DefaultCodeFormatterOptions.getEclipseDefaultSettings();
494
	preferencesWithoutComment.comment_format_line_comment = false;
495
	preferencesWithoutComment.comment_format_block_comment = false;
496
	preferencesWithoutComment.comment_format_javadoc_comment = false;
497
	DefaultCodeFormatter codeFormatterWithoutComment = new DefaultCodeFormatter(preferencesWithoutComment);
498
499
	TextEdit edit = codeFormatterWithoutComment.format(kind, source, offset, length, indentationLevel, lineSeparator);//$NON-NLS-1$
500
	if (edit == null) return false;
501
	String initialResult = org.eclipse.jdt.internal.core.util.Util.editedString(source, edit);
502
503
	int count = 1;
504
	String result = initialResult;
505
	String previousResult = result;
506
	while (count++ < FORMAT_REPEAT) {
507
		edit = codeFormatterWithoutComment.format(kind, result, 0, result.length(), indentationLevel, lineSeparator);//$NON-NLS-1$
508
		if (edit == null) return false;
509
		previousResult = result;
510
		result = org.eclipse.jdt.internal.core.util.Util.editedString(result, edit);
511
	}
512
	return previousResult.equals(result);
513
}
514
*/
515
780
String runFormatter(CodeFormatter codeFormatter, String source, int kind, int indentationLevel, int offset, int length, String lineSeparator) {
516
String runFormatter(CodeFormatter codeFormatter, String source, int kind, int indentationLevel, int offset, int length, String lineSeparator) {
781
	TextEdit edit = codeFormatter.format(kind, source, offset, length, indentationLevel, lineSeparator);//$NON-NLS-1$
517
	TextEdit edit = codeFormatter.format(kind, source, offset, length, indentationLevel, lineSeparator);//$NON-NLS-1$
782
	if (edit == null) return null;
518
	try {
783
	String result = org.eclipse.jdt.internal.core.util.Util.editedString(source, edit);
519
		assertNotNull("Formatted source should not be null!", edit);
520
	}
521
	catch (ComparisonFailure cf) {
522
		FAILURES[NO_OUTPUT_FAILURE].failures.add(this.path);
523
		throw cf;
524
	}
525
	catch (AssertionFailedError afe) {
526
		FAILURES[NO_OUTPUT_FAILURE].failures.add(this.path);
527
		throw afe;
528
	}
529
	String initialResult = org.eclipse.jdt.internal.core.util.Util.editedString(source, edit);
784
530
785
	int count = 1;
531
	int count = 1;
786
	if (COMPARE == null && length == source.length()) {
532
	String result = initialResult;
787
		String previousResult = result;
533
	String previousResult = result;
788
		while (count++ < FORMAT_REPEAT) {
534
	while (count++ < FORMAT_REPEAT) {
789
			edit = codeFormatter.format(kind, result, 0, result.length(), indentationLevel, lineSeparator);//$NON-NLS-1$
535
		edit = codeFormatter.format(kind, result, 0, result.length(), indentationLevel, lineSeparator);//$NON-NLS-1$
790
			if (edit == null) return null;
536
		if (edit == null) return null;
791
			previousResult = result;
537
		previousResult = result;
792
			result = org.eclipse.jdt.internal.core.util.Util.editedString(result, edit);
538
		result = org.eclipse.jdt.internal.core.util.Util.editedString(result, edit);
793
		}
539
	}
794
		if (!previousResult.equals(result)) {
540
	if (!previousResult.equals(result)) {
795
			switch (IGNORE_SPACES) {
541
796
				case ALL_SPACES:
542
		// Try to compare without leading spaces
797
					String trimmedExpected = ModelTestsUtil.removeWhiteSpace(previousResult);
543
		String trimmedExpected = ModelTestsUtil.trimLinesLeadingWhitespaces(previousResult);
798
					String trimmedActual= ModelTestsUtil.removeWhiteSpace(result);
544
		String trimmedActual= ModelTestsUtil.trimLinesLeadingWhitespaces(result);
799
					if (trimmedExpected.equals(trimmedActual)) {
545
		if (trimmedExpected.equals(trimmedActual)) {
800
						this.whitespacesFailures.add(this.path);
546
			FAILURES[REFORMATTING_LEADING_FAILURE].failures.add(this.path);
801
						this.hasSpaceFailure = true;
547
			this.hasSpaceFailure = true;
802
						return previousResult;
548
			return initialResult;
803
					}
549
		}
804
					break;
550
		
805
				case LINES_LEADING_SPACES:
551
		// Try to compare without spaces at all
806
					trimmedExpected = ModelTestsUtil.trimLinesLeadingWhitespaces(previousResult);
552
		if (ModelTestsUtil.removeWhiteSpace(previousResult).equals(ModelTestsUtil.removeWhiteSpace(result))) {
807
					trimmedActual= ModelTestsUtil.trimLinesLeadingWhitespaces(result);
553
			FAILURES[REFORMATTING_WHITESPACES_FAILURE].failures.add(this.path);
808
					if (trimmedExpected.equals(trimmedActual)) {
554
			this.hasSpaceFailure = true;
809
						this.leadingWhitespacesFailures.add(this.path);
555
			return initialResult;
810
						this.hasSpaceFailure = true;
556
		}
811
						return previousResult;
557
812
					}
558
		/*
813
					if (ModelTestsUtil.removeWhiteSpace(previousResult).equals(ModelTestsUtil.removeWhiteSpace(result))) {
559
		// Try to see if the formatting also fails without comments
814
						this.whitespacesFailures.add(this.path);
560
		if (!runFormatterWithoutComments(null, source, kind, indentationLevel, offset, length, lineSeparator)) {
815
						this.hasSpaceFailure = true;
561
			return initialResult;
816
						return previousResult;
562
		}
817
					}
563
818
					break;
564
		// format without comments is OK => there's a problem with comment formatting
819
			}
565
		String counterString = counterToString(count-1);
820
			if (!isExpectedFailure()) {
566
		assertSourceEquals(counterString+" formatting is different from first one!", previousResult, result);
821
				String counterString = counterToString(count-1);
567
		*/
822
				assertSourceEquals(counterString+" formatting is different from first one!", Util.convertToIndependantLineDelimiter(previousResult), Util.convertToIndependantLineDelimiter(result));
568
		if (!isExpectedFailure()) {
569
			String counterString = counterToString(count-1);
570
			try {
571
				assertSourceEquals(counterString+" formatting is different from first one!", previousResult, result);
572
			}
573
			catch (ComparisonFailure cf) {
574
				FAILURES[REFORMATTING_FAILURE].failures.add(this.path);
575
				throw cf;
576
			}
577
			catch (AssertionFailedError afe) {
578
				FAILURES[REFORMATTING_FAILURE].failures.add(this.path);
579
				throw afe;
823
			}
580
			}
824
			result = previousResult;
825
		}
581
		}
826
	}
582
	}
827
	return result;
583
	return initialResult;
828
}
584
}
829
585
830
public void testCompare() throws IOException, Exception {
586
public void testCompare() throws IOException, Exception {
(-)src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsBugsTest.java (+202 lines)
Lines 977-980 Link Here
977
		1 /* indentation level */
977
		1 /* indentation level */
978
	);
978
	);
979
}
979
}
980
981
/**
982
 * @bug 236230: [formatter] SIOOBE while formatting a compilation unit.
983
 * @test Ensure that no exception occurs while formatting
984
 * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=236230"
985
 */
986
public void testBug236230() throws JavaModelException {
987
	String source = 
988
		"/**\n" + 
989
		" * Need a javadoc comment before to get the exception.\n" + 
990
		" */\n" + 
991
		"public class Test {\n" + 
992
		"\n" + 
993
		"  /**\n" + 
994
		"   * <p>If there is an authority, it is:\n" + 
995
		"   * <pre>\n" + 
996
		"   *   //authority/device/pathSegment1/pathSegment2...</pre>\n" + 
997
		"   */\n" + 
998
		"  public String devicePath() {\n" + 
999
		"	  return null;\n" + 
1000
		"  }\n" + 
1001
		"}\n";
1002
	formatSource(source,
1003
		"/**\n" + 
1004
		" * Need a javadoc comment before to get the exception.\n" + 
1005
		" */\n" + 
1006
		"public class Test {\n" + 
1007
		"\n" + 
1008
		"	/**\n" + 
1009
		"	 * <p>\n" + 
1010
		"	 * If there is an authority, it is:\n" + 
1011
		"	 * \n" + 
1012
		"	 * <pre>\n" + 
1013
		"	 * // authority/device/pathSegment1/pathSegment2...\n" + 
1014
		"	 * </pre>\n" + 
1015
		"	 */\n" + 
1016
		"	public String devicePath() {\n" + 
1017
		"		return null;\n" + 
1018
		"	}\n" + 
1019
		"}\n"
1020
	);
1021
}
1022
public void testBug236230b() throws JavaModelException {
1023
	String source = 
1024
		"/**\n" + 
1025
		" * Need a javadoc comment before to get the exception.\n" + 
1026
		" */\n" + 
1027
		"public class Test {\n" + 
1028
		"\n" + 
1029
		"  /**\n" + 
1030
		"   * <p>If there is an authority, it is:\n" + 
1031
		"   * <pre>//authority/device/pathSegment1/pathSegment2...</pre>\n" + 
1032
		"   */\n" + 
1033
		"  public String devicePath() {\n" + 
1034
		"	  return null;\n" + 
1035
		"  }\n" + 
1036
		"}\n";
1037
	formatSource(source,
1038
		"/**\n" + 
1039
		" * Need a javadoc comment before to get the exception.\n" + 
1040
		" */\n" + 
1041
		"public class Test {\n" + 
1042
		"\n" + 
1043
		"	/**\n" + 
1044
		"	 * <p>\n" + 
1045
		"	 * If there is an authority, it is:\n" + 
1046
		"	 * \n" + 
1047
		"	 * <pre>\n" + 
1048
		"	 * // authority/device/pathSegment1/pathSegment2...\n" + 
1049
		"	 * </pre>\n" + 
1050
		"	 */\n" + 
1051
		"	public String devicePath() {\n" + 
1052
		"		return null;\n" + 
1053
		"	}\n" + 
1054
		"}\n"
1055
	);
1056
}
1057
public void testBug236230c() throws JavaModelException {
1058
	this.preferences.comment_format_header = true;
1059
	String source = 
1060
		"/**\n" + 
1061
		" * Need a javadoc comment before to get the exception.\n" + 
1062
		" */\n" + 
1063
		"public class Test {\n" + 
1064
		"\n" + 
1065
		"  /**\n" + 
1066
		"   * <p>If there is an authority, it is:\n" + 
1067
		"   * <pre>\n" +
1068
		"			import java.util.List;\n" +
1069
		"			//            CU         snippet\n" +
1070
		"			public class X implements List {}\n" +
1071
		"		</pre>\n" + 
1072
		"   */\n" + 
1073
		"  public String devicePath() {\n" + 
1074
		"	  return null;\n" + 
1075
		"  }\n" + 
1076
		"}\n";
1077
	formatSource(source,
1078
		"/**\n" + 
1079
		" * Need a javadoc comment before to get the exception.\n" + 
1080
		" */\n" + 
1081
		"public class Test {\n" + 
1082
		"\n" + 
1083
		"	/**\n" + 
1084
		"	 * <p>\n" + 
1085
		"	 * If there is an authority, it is:\n" + 
1086
		"	 * \n" + 
1087
		"	 * <pre>\n" + 
1088
		"	 * import java.util.List;\n" + 
1089
		"	 * \n" + 
1090
		"	 * // CU snippet\n" + 
1091
		"	 * public class X implements List {\n" + 
1092
		"	 * }\n" + 
1093
		"	 * </pre>\n" + 
1094
		"	 */\n" + 
1095
		"	public String devicePath() {\n" + 
1096
		"		return null;\n" + 
1097
		"	}\n" + 
1098
		"}\n"
1099
	);
1100
}
1101
public void testBug236230d() throws JavaModelException {
1102
	String source = 
1103
		"/**\n" + 
1104
		" * Need a javadoc comment before to get the exception.\n" + 
1105
		" */\n" + 
1106
		"public class Test {\n" + 
1107
		"\n" + 
1108
		"  /**\n" + 
1109
		"   * <p>If there is an authority, it is:\n" + 
1110
		"   * <pre>\n" +
1111
		"			//class	body		snippet\n" +
1112
		"			public class X {}\n" +
1113
		"		</pre>\n" + 
1114
		"   */\n" + 
1115
		"  public String devicePath() {\n" + 
1116
		"	  return null;\n" + 
1117
		"  }\n" + 
1118
		"}\n";
1119
	// TODO (frederic) line comment should be formatted when F_INCLUDE_COMMENTS
1120
	// flag will work for all snippet kinds
1121
	formatSource(source,
1122
		"/**\n" + 
1123
		" * Need a javadoc comment before to get the exception.\n" + 
1124
		" */\n" + 
1125
		"public class Test {\n" + 
1126
		"\n" + 
1127
		"	/**\n" + 
1128
		"	 * <p>\n" + 
1129
		"	 * If there is an authority, it is:\n" + 
1130
		"	 * \n" + 
1131
		"	 * <pre>\n" + 
1132
		"	 * //class	body		snippet\n" + 
1133
		"	 * public class X {\n" + 
1134
		"	 * }\n" + 
1135
		"	 * </pre>\n" + 
1136
		"	 */\n" + 
1137
		"	public String devicePath() {\n" + 
1138
		"		return null;\n" + 
1139
		"	}\n" + 
1140
		"}\n"
1141
	);
1142
}
1143
// Following tests showed possible regressions while implementing the fix...
1144
public void testBug236230e() throws JavaModelException {
1145
	String source = 
1146
		"public class X02 {\n" + 
1147
		"\n" + 
1148
		"\n" + 
1149
		"	/**\n" + 
1150
		"	/**\n" + 
1151
		"	 * Removes the Java nature from the project.\n" + 
1152
		"	 */\n" + 
1153
		"	void foo() {\n" + 
1154
		"	}\n" + 
1155
		"}\n";
1156
	formatSource(source,
1157
		"public class X02 {\n" + 
1158
		"\n" + 
1159
		"	/**\n" + 
1160
		"	 * /** Removes the Java nature from the project.\n" + 
1161
		"	 */\n" + 
1162
		"	void foo() {\n" + 
1163
		"	}\n" + 
1164
		"}\n"
1165
	);
1166
}
1167
public void testBug236230f() throws JavaModelException {
1168
	String source = 
1169
		"public class X03 {\n" + 
1170
		"  /** The value of <tt>System.getProperty(\"java.version\")<tt>. **/\n" + 
1171
		"  static final String JAVA_VERSION = System.getProperty(\"java.version\");\n" + 
1172
		"\n" + 
1173
		"}\n";
1174
	formatSource(source,
1175
		"public class X03 {\n" + 
1176
		"	/** The value of <tt>System.getProperty(\"java.version\")<tt>. **/\n" + 
1177
		"	static final String JAVA_VERSION = System.getProperty(\"java.version\");\n" + 
1178
		"\n" + 
1179
		"}\n"
1180
	);
1181
}
980
}
1182
}
(-)src/org/eclipse/jdt/core/tests/dom/ASTConverterJavadocTest.java (-217 / +31 lines)
Lines 30-35 Link Here
30
import org.eclipse.jdt.core.dom.*;
30
import org.eclipse.jdt.core.dom.*;
31
import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
31
import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
32
32
33
/**
34
 * Class to test DOM/AST nodes built for Javadoc comments.
35
 * 
36
 * Most of tests are 'automatic'. It means that to add a new tests, you only need to
37
 * create one or several CUs and put them in org.eclipse.jdt.core.model.tests/workspace/Converter/src/javadoc/testXXX
38
 * folder and add the corresponding test in this class:
39
 * <pre>
40
 * public void testXXX() throws JavaModelException {
41
 * 	verifyComments("testXXX");
42
 * }
43
 * </pre>
44
 * 
45
 * Note that when a test fails, the easiest way to debug it is to open
46
 * a runtime workbench, create a project 'Converter', delete the default 'src' source folder
47
 * and replace it by a linked source to the 'src' folder of org.eclipse.jdt.core.model.tests/workspace/Converter/src
48
 * in your workspace.
49
 * 
50
 * Then open the CU on which the test fails in a ASTView and verify the offset/length
51
 * of the offending node located at the positions displayed in the console when the test failed...
52
 * 
53
 * Since 3.4, the failing test also provides the comparision between the source of the comment
54
 * and the string get from the built DOM/AST nodes in the comment (see {@link ASTConverterJavadocFlattener})
55
 * but this may be not enough to see precisely the origin of the problem.
56
 */
33
public class ASTConverterJavadocTest extends ConverterTestSetup {
57
public class ASTConverterJavadocTest extends ConverterTestSetup {
34
58
35
	// Flag to know whether Converter directory should be copied from org.eclipse.jdt.core.tests.model project
59
	// Flag to know whether Converter directory should be copied from org.eclipse.jdt.core.tests.model project
Lines 244-464 Link Here
244
		return runConversion(source, unitName, project);
268
		return runConversion(source, unitName, project);
245
	}
269
	}
246
270
247
// NOT USED
248
//	class ASTConverterJavadocFlattener extends ASTVisitor {
249
//
250
//		/**
251
//		 * The string buffer into which the serialized representation of the AST is
252
//		 * written.
253
//		 */
254
//		private StringBuffer buffer;
255
//		
256
//		private String comment;
257
//		
258
//		/**
259
//		 * Creates a new AST printer.
260
//		 */
261
//		ASTConverterJavadocFlattener(String comment) {
262
//			buffer = new StringBuffer();
263
//			comment = comment;
264
//		}
265
//		
266
//		/**
267
//		 * Returns the string accumulated in the visit.
268
//		 *
269
//		 * @return the serialized 
270
//		 */
271
//		public String getResult() {
272
//			return buffer.toString();
273
//		}
274
//		
275
//		/**
276
//		 * Resets this printer so that it can be used again.
277
//		 */
278
//		public void reset() {
279
//			buffer.setLength(0);
280
//		}
281
//
282
//		/*
283
//		 * @see ASTVisitor#visit(ArrayType)
284
//		 */
285
//		public boolean visit(ArrayType node) {
286
//			node.getComponentType().accept(this);
287
//			buffer.append("[]");//$NON-NLS-1$
288
//			return false;
289
//		}
290
//	
291
//		/*
292
//		 * @see ASTVisitor#visit(BlockComment)
293
//		 * @since 3.0
294
//		 */
295
//		public boolean visit(BlockComment node) {
296
//			buffer.append(comment);
297
//			return false;
298
//		}
299
//	
300
//		/*
301
//		 * @see ASTVisitor#visit(Javadoc)
302
//		 */
303
//		public boolean visit(Javadoc node) {
304
//			
305
//			// ignore deprecated node.getComment()
306
//			buffer.append("/**");//$NON-NLS-1$
307
//			ASTNode e = null;
308
//			int start = 3;
309
//			for (Iterator it = node.tags().iterator(); it.hasNext(); ) {
310
//				e = (ASTNode) it.next();
311
//				try {
312
//					buffer.append(comment.substring(start, e.getStartPosition()-node.getStartPosition()));
313
//					start = e.getStartPosition()-node.getStartPosition();
314
//				} catch (IndexOutOfBoundsException ex) {
315
//					// do nothing
316
//				}
317
//				e.accept(this);
318
//				start += e.getLength();
319
//			}
320
//			buffer.append(comment.substring(start, node.getLength()));
321
//			return false;
322
//		}
323
//	
324
//		/*
325
//		 * @see ASTVisitor#visit(LineComment)
326
//		 * @since 3.0
327
//		 */
328
//		public boolean visit(LineComment node) {
329
//			buffer.append(comment);
330
//			return false;
331
//		}
332
//	
333
//		/*
334
//		 * @see ASTVisitor#visit(MemberRef)
335
//		 * @since 3.0
336
//		 */
337
//		public boolean visit(MemberRef node) {
338
//			if (node.getQualifier() != null) {
339
//				node.getQualifier().accept(this);
340
//			}
341
//			buffer.append("#");//$NON-NLS-1$
342
//			node.getName().accept(this);
343
//			return true;
344
//		}
345
//		
346
//		/*
347
//		 * @see ASTVisitor#visit(MethodRef)
348
//		 * @since 3.0
349
//		 */
350
//		public boolean visit(MethodRef node) {
351
//			if (node.getQualifier() != null) {
352
//				node.getQualifier().accept(this);
353
//			}
354
//			buffer.append("#");//$NON-NLS-1$
355
//			node.getName().accept(this);
356
//			buffer.append("(");//$NON-NLS-1$
357
//			for (Iterator it = node.parameters().iterator(); it.hasNext(); ) {
358
//				MethodRefParameter e = (MethodRefParameter) it.next();
359
//				e.accept(this);
360
//				if (it.hasNext()) {
361
//					buffer.append(",");//$NON-NLS-1$
362
//				}
363
//			}
364
//			buffer.append(")");//$NON-NLS-1$
365
//			return true;
366
//		}
367
//		
368
//		/*
369
//		 * @see ASTVisitor#visit(MethodRefParameter)
370
//		 * @since 3.0
371
//		 */
372
//		public boolean visit(MethodRefParameter node) {
373
//			node.getType().accept(this);
374
//			if (node.getName() != null) {
375
//				buffer.append(" ");//$NON-NLS-1$
376
//				node.getName().accept(this);
377
//			}
378
//			return true;
379
//		}
380
//
381
//		/*
382
//		 * @see ASTVisitor#visit(TagElement)
383
//		 * @since 3.0
384
//		 */
385
//		public boolean visit(TagElement node) {
386
//			Javadoc javadoc = null;
387
//			int start = 0;
388
//			if (node.isNested()) {
389
//				// nested tags are always enclosed in braces
390
//				buffer.append("{");//$NON-NLS-1$
391
//				javadoc = (Javadoc) node.getParent().getParent();
392
//				start++;
393
//			} else {
394
//				javadoc = (Javadoc) node.getParent();
395
//			}
396
//			start += node.getStartPosition()-javadoc.getStartPosition();
397
//			if (node.getTagName() != null) {
398
//				buffer.append(node.getTagName());
399
//				start += node.getTagName().length();
400
//			}
401
//			for (Iterator it = node.fragments().iterator(); it.hasNext(); ) {
402
//				ASTNode e = (ASTNode) it.next();
403
//				try {
404
//					buffer.append(comment.substring(start, e.getStartPosition()-javadoc.getStartPosition()));
405
//					start = e.getStartPosition()-javadoc.getStartPosition();
406
//				} catch (IndexOutOfBoundsException ex) {
407
//					// do nothing
408
//				}
409
//				start += e.getLength();
410
//				e.accept(this);
411
//			}
412
//			if (node.isNested()) {
413
//				buffer.append("}");//$NON-NLS-1$
414
//			}
415
//			return true;
416
//		}
417
//		
418
//		/*
419
//		 * @see ASTVisitor#visit(TextElement)
420
//		 * @since 3.0
421
//		 */
422
//		public boolean visit(TextElement node) {
423
//			buffer.append(node.getText());
424
//			return false;
425
//		}
426
//
427
//		/*
428
//		 * @see ASTVisitor#visit(PrimitiveType)
429
//		 */
430
//		public boolean visit(PrimitiveType node) {
431
//			buffer.append(node.getPrimitiveTypeCode().toString());
432
//			return false;
433
//		}
434
//	
435
//		/*
436
//		 * @see ASTVisitor#visit(QualifiedName)
437
//		 */
438
//		public boolean visit(QualifiedName node) {
439
//			node.getQualifier().accept(this);
440
//			buffer.append(".");//$NON-NLS-1$
441
//			node.getName().accept(this);
442
//			return false;
443
//		}
444
//
445
//		/*
446
//		 * @see ASTVisitor#visit(SimpleName)
447
//		 */
448
//		public boolean visit(SimpleName node) {
449
//			buffer.append(node.getIdentifier());
450
//			return false;
451
//		}
452
//
453
//		/*
454
//		 * @see ASTVisitor#visit(SimpleName)
455
//		 */
456
//		public boolean visit(SimpleType node) {
457
//			node.getName().accept(this);
458
//			return false;
459
//		}
460
//	}
461
462
	private char getNextChar(char[] source, int idx) {
271
	private char getNextChar(char[] source, int idx) {
463
			// get next char
272
			// get next char
464
			char ch = source[idx];
273
			char ch = source[idx];
Lines 820-826 Link Here
820
	 */
629
	 */
821
	private void verifyPositions(Javadoc docComment, char[] source) {
630
	private void verifyPositions(Javadoc docComment, char[] source) {
822
		boolean stop = stopOnFailure;
631
		boolean stop = stopOnFailure;
823
//		stopOnFailure = false;
632
		stopOnFailure = false;
824
		// Verify javadoc start and end position
633
		// Verify javadoc start and end position
825
		int start = docComment.getStartPosition();
634
		int start = docComment.getStartPosition();
826
		int end = start+docComment.getLength()-1;
635
		int end = start+docComment.getLength()-1;
Lines 845-851 Link Here
845
		assumeTrue(prefix+"Misplaced javadoc end at <"+tagStart+'>', source[tagStart-1] == '*' && source[tagStart] == '/');
654
		assumeTrue(prefix+"Misplaced javadoc end at <"+tagStart+'>', source[tagStart-1] == '*' && source[tagStart] == '/');
846
		assumeEquals(prefix+"Wrong javadoc length at <"+end+">: ", tagStart, end);
655
		assumeEquals(prefix+"Wrong javadoc length at <"+end+">: ", tagStart, end);
847
		stopOnFailure = stop;
656
		stopOnFailure = stop;
848
		assertTrue(!stop || failures.size()==0);
657
		if (stop && failures.size() > 0) {
658
			String expected = new String(source, docComment.getStartPosition(), docComment.getLength());
659
			ASTConverterJavadocFlattener flattener = new ASTConverterJavadocFlattener(expected);
660
			docComment.accept(flattener);
661
			assertEquals("Unexpected errors while verifying javadoc comment positions!", expected, flattener.getResult());
662
		}
849
	}
663
	}
850
664
851
	/**
665
	/**
(-)src/org/eclipse/jdt/core/tests/dom/ASTConverterJavadocFlattener.java (+236 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.core.tests.dom;
12
13
import java.util.Iterator;
14
15
import org.eclipse.jdt.core.dom.*;
16
17
public class ASTConverterJavadocFlattener extends ASTVisitor {
18
19
	/**
20
	 * The string buffer into which the serialized representation of the AST is
21
	 * written.
22
	 */
23
	private StringBuffer buffer;
24
	private int indent = 0;
25
	private String comment;
26
		
27
/**
28
 * Creates a new AST printer.
29
 */
30
ASTConverterJavadocFlattener(String comment) {
31
	buffer = new StringBuffer();
32
	this.comment = comment;
33
}
34
35
/**
36
 * Returns the string accumulated in the visit.
37
 *
38
 * @return the serialized 
39
 */
40
public String getResult() {
41
	return buffer.toString();
42
}
43
44
/**
45
 * Resets this printer so that it can be used again.
46
 */
47
public void reset() {
48
	buffer.setLength(0);
49
}
50
51
/*
52
 * @see ASTVisitor#visit(ArrayType)
53
 */
54
public boolean visit(ArrayType node) {
55
	node.getComponentType().accept(this);
56
	buffer.append("[]");//$NON-NLS-1$
57
	return false;
58
}
59
60
/*
61
 * @see ASTVisitor#visit(BlockComment)
62
 * @since 3.0
63
 */
64
public boolean visit(BlockComment node) {
65
	buffer.append(comment);
66
	return false;
67
}
68
69
/*
70
 * @see ASTVisitor#visit(Javadoc)
71
 */
72
public boolean visit(Javadoc javadoc) {
73
	printIndent();
74
	this.buffer.append("/**");//$NON-NLS-1$
75
	for (Iterator it = javadoc.tags().iterator(); it.hasNext(); ) {
76
		ASTNode e = (ASTNode) it.next();
77
		e.accept(this);
78
	}
79
	this.buffer.append("\n */\n");//$NON-NLS-1$
80
	return false;
81
}
82
83
private void printIndent() {
84
	for (int i=0; i<this.indent; i++) {
85
		buffer.append('\t');
86
	}
87
}
88
89
/*
90
private void printNewLine() {
91
	buffer.append('\n');
92
	printIndent();
93
	buffer.append(" * ");
94
}
95
*/
96
97
/*
98
 * @see ASTVisitor#visit(LineComment)
99
 * @since 3.0
100
 */
101
public boolean visit(LineComment node) {
102
	buffer.append(comment);
103
	return false;
104
}
105
106
/*
107
 * @see ASTVisitor#visit(MemberRef)
108
 * @since 3.0
109
 */
110
public boolean visit(MemberRef node) {
111
	if (node.getQualifier() != null) {
112
		node.getQualifier().accept(this);
113
	}
114
	buffer.append("#");//$NON-NLS-1$
115
	node.getName().accept(this);
116
	return true;
117
}
118
119
/*
120
 * @see ASTVisitor#visit(MethodRef)
121
 * @since 3.0
122
 */
123
public boolean visit(MethodRef node) {
124
	if (node.getQualifier() != null) {
125
		node.getQualifier().accept(this);
126
	}
127
	buffer.append("#");//$NON-NLS-1$
128
	node.getName().accept(this);
129
	buffer.append("(");//$NON-NLS-1$
130
	for (Iterator it = node.parameters().iterator(); it.hasNext(); ) {
131
		MethodRefParameter e = (MethodRefParameter) it.next();
132
		e.accept(this);
133
		if (it.hasNext()) {
134
			buffer.append(",");//$NON-NLS-1$
135
		}
136
	}
137
	buffer.append(")");//$NON-NLS-1$
138
	return true;
139
}
140
141
/*
142
 * @see ASTVisitor#visit(MethodRefParameter)
143
 * @since 3.0
144
 */
145
public boolean visit(MethodRefParameter node) {
146
	node.getType().accept(this);
147
	if (node.getName() != null) {
148
		buffer.append(" ");//$NON-NLS-1$
149
		node.getName().accept(this);
150
	}
151
	return true;
152
}
153
154
/*
155
 * @see ASTVisitor#visit(TagElement)
156
 * @since 3.0
157
 */
158
public boolean visit(TagElement node) {
159
	if (node.isNested()) {
160
		// nested tags are always enclosed in braces
161
		this.buffer.append("{");//$NON-NLS-1$
162
	} else {
163
		// top-level tags always begin on a new line
164
		this.buffer.append("\n * ");//$NON-NLS-1$
165
	}
166
	boolean previousRequiresWhiteSpace = false;
167
	if (node.getTagName() != null) {
168
		this.buffer.append(node.getTagName());
169
		previousRequiresWhiteSpace = true;
170
	}
171
	boolean previousRequiresNewLine = false;
172
	for (Iterator it = node.fragments().iterator(); it.hasNext(); ) {
173
		ASTNode e = (ASTNode) it.next();
174
		// assume text elements include necessary leading and trailing whitespace
175
		// but Name, MemberRef, MethodRef, and nested TagElement do not include white space
176
		boolean currentIncludesWhiteSpace = (e instanceof TextElement);
177
		if (previousRequiresNewLine && currentIncludesWhiteSpace) {
178
			this.buffer.append("\n * ");//$NON-NLS-1$
179
		}
180
		previousRequiresNewLine = currentIncludesWhiteSpace;
181
		// add space if required to separate
182
		if (previousRequiresWhiteSpace && !currentIncludesWhiteSpace) {
183
			this.buffer.append(" "); //$NON-NLS-1$
184
		}
185
		e.accept(this);
186
		previousRequiresWhiteSpace = !currentIncludesWhiteSpace && !(e instanceof TagElement);
187
	}
188
	if (node.isNested()) {
189
		this.buffer.append("}");//$NON-NLS-1$
190
	}
191
	return false;
192
}
193
194
/*
195
 * @see ASTVisitor#visit(TextElement)
196
 * @since 3.0
197
 */
198
public boolean visit(TextElement node) {
199
	buffer.append(node.getText());
200
	return false;
201
}
202
203
/*
204
 * @see ASTVisitor#visit(PrimitiveType)
205
 */
206
public boolean visit(PrimitiveType node) {
207
	buffer.append(node.getPrimitiveTypeCode().toString());
208
	return false;
209
}
210
211
/*
212
 * @see ASTVisitor#visit(QualifiedName)
213
 */
214
public boolean visit(QualifiedName node) {
215
	node.getQualifier().accept(this);
216
	buffer.append(".");//$NON-NLS-1$
217
	node.getName().accept(this);
218
	return false;
219
}
220
221
/*
222
 * @see ASTVisitor#visit(SimpleName)
223
 */
224
public boolean visit(SimpleName node) {
225
	buffer.append(node.getIdentifier());
226
	return false;
227
}
228
229
/*
230
 * @see ASTVisitor#visit(SimpleName)
231
 */
232
public boolean visit(SimpleType node) {
233
	node.getName().accept(this);
234
	return false;
235
}
236
}
(-)formatter/org/eclipse/jdt/internal/formatter/Scribe.java (-1 / +2 lines)
Lines 1715-1722 Link Here
1715
		}
1715
		}
1716
		
1716
		
1717
		// 3 - process snippet (@see JavaDocRegion#formatCodeSnippet)
1717
		// 3 - process snippet (@see JavaDocRegion#formatCodeSnippet)
1718
		// include comments in case of line comments are present in the snippet
1718
		String formattedSnippet = convertedSnippet;
1719
		String formattedSnippet = convertedSnippet;
1719
		TextEdit edit= CommentFormatterUtil.format2(CodeFormatter.K_UNKNOWN, convertedSnippet, 0, this.lineSeparator, this.formatter.preferences.getMap());
1720
		TextEdit edit= CommentFormatterUtil.format2(CodeFormatter.K_UNKNOWN | CodeFormatter.F_INCLUDE_COMMENTS, convertedSnippet, 0, this.lineSeparator, this.formatter.preferences.getMap());
1720
		if (edit != null) {
1721
		if (edit != null) {
1721
			formattedSnippet= CommentFormatterUtil.evaluateFormatterEdit(convertedSnippet, edit, null);
1722
			formattedSnippet= CommentFormatterUtil.evaluateFormatterEdit(convertedSnippet, edit, null);
1722
		}
1723
		}
(-)formatter/org/eclipse/jdt/internal/formatter/FormatterCommentParser.java (-16 / +1 lines)
Lines 475-496 Link Here
475
	}
475
	}
476
476
477
	// Add the text
477
	// Add the text
478
	int textEnd = end;
478
	FormatJavadocText text = new FormatJavadocText(start, end-1, lineStart, htmlIndex, htmlDepth);
479
	if (this.javadocTextEnd > 0 && end >= this.javadocTextEnd) {
480
		// Special case on javadoc text end, need to retrieve the space
481
		// position by rescanning the text
482
		int restart = this.spacePosition == -1 ? start : this.spacePosition;
483
		this.scanner.resetTo(restart, end-1/* before last star*/);
484
		try {
485
			if (this.scanner.getNextToken() == TerminalTokens.TokenNameEOF) {
486
				textEnd = this.spacePosition;
487
			}
488
		}
489
		catch (InvalidInputException iie) {
490
			// do nothing
491
		}
492
	}
493
	FormatJavadocText text = new FormatJavadocText(start, textEnd-1, lineStart, htmlIndex, htmlDepth);
494
	previousBlock.addText(text);
479
	previousBlock.addText(text);
495
	previousBlock.sourceStart = previousStart;
480
	previousBlock.sourceStart = previousStart;
496
	if (lineStart == previousBlock.lineStart) {
481
	if (lineStart == previousBlock.lineStart) {
(-)formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java (-6 / +8 lines)
Lines 25-30 Link Here
25
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
25
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
26
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
26
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
27
import org.eclipse.jdt.internal.compiler.parser.Scanner;
27
import org.eclipse.jdt.internal.compiler.parser.Scanner;
28
import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
28
import org.eclipse.jdt.internal.compiler.util.Util;
29
import org.eclipse.jdt.internal.compiler.util.Util;
29
import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil;
30
import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil;
30
import org.eclipse.jdt.internal.formatter.comment.CommentRegion;
31
import org.eclipse.jdt.internal.formatter.comment.CommentRegion;
Lines 487-494 Link Here
487
488
488
	private TextEdit probeFormatting(String source, int indentationLevel, String lineSeparator, IRegion[] regions, boolean includeComments) {
489
	private TextEdit probeFormatting(String source, int indentationLevel, String lineSeparator, IRegion[] regions, boolean includeComments) {
489
		if (PROBING_SCANNER == null) {
490
		if (PROBING_SCANNER == null) {
490
			// scanner use to check if the kind could be K_JAVA_DOC, K_MULTI_LINE_COMMENT or K_SINGLE_LINE_COMMENT 
491
			// scanner use to check if the kind could be K_JAVA_DOC, K_MULTI_LINE_COMMENT or K_SINGLE_LINE_COMMENT
491
			PROBING_SCANNER = new Scanner(true, true, false/*nls*/, ClassFileConstants.JDK1_3, ClassFileConstants.JDK1_3, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
492
			// do not tokenize white spaces to get single comments even with spaces before...
493
			PROBING_SCANNER = new Scanner(true, false/*do not tokenize whitespaces*/, false/*nls*/, ClassFileConstants.JDK1_6, ClassFileConstants.JDK1_6, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
492
		}
494
		}
493
		PROBING_SCANNER.setSource(source.toCharArray());
495
		PROBING_SCANNER.setSource(source.toCharArray());
494
		
496
		
Lines 496-517 Link Here
496
		int offset = coveredRegion.getOffset();
498
		int offset = coveredRegion.getOffset();
497
		int length = coveredRegion.getLength();
499
		int length = coveredRegion.getLength();
498
		
500
		
499
		PROBING_SCANNER.resetTo(offset, offset + length);
501
		PROBING_SCANNER.resetTo(offset, offset + length - 1);
500
		try {
502
		try {
501
			int kind = -1;
503
			int kind = -1;
502
			switch(PROBING_SCANNER.getNextToken()) {
504
			switch(PROBING_SCANNER.getNextToken()) {
503
				case ITerminalSymbols.TokenNameCOMMENT_BLOCK :
505
				case ITerminalSymbols.TokenNameCOMMENT_BLOCK :
504
					if (PROBING_SCANNER.getCurrentTokenEndPosition() == offset + length - 1) {
506
					if (PROBING_SCANNER.getNextToken() == TerminalTokens.TokenNameEOF) {
505
						kind = K_MULTI_LINE_COMMENT;
507
						kind = K_MULTI_LINE_COMMENT;
506
					}
508
					}
507
					break;
509
					break;
508
				case ITerminalSymbols.TokenNameCOMMENT_LINE :
510
				case ITerminalSymbols.TokenNameCOMMENT_LINE :
509
					if (PROBING_SCANNER.getCurrentTokenEndPosition() == offset + length - 1) {
511
					if (PROBING_SCANNER.getNextToken() == TerminalTokens.TokenNameEOF) {
510
						kind = K_SINGLE_LINE_COMMENT;
512
						kind = K_SINGLE_LINE_COMMENT;
511
					}
513
					}
512
					break;
514
					break;
513
				case ITerminalSymbols.TokenNameCOMMENT_JAVADOC :
515
				case ITerminalSymbols.TokenNameCOMMENT_JAVADOC :
514
					if (PROBING_SCANNER.getCurrentTokenEndPosition() == offset + length - 1) {
516
					if (PROBING_SCANNER.getNextToken() == TerminalTokens.TokenNameEOF) {
515
						kind = K_JAVA_DOC;
517
						kind = K_JAVA_DOC;
516
					}
518
					}
517
					break;
519
					break;
(-)compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java (-66 / +40 lines)
Lines 62-68 Link Here
62
	protected int javadocTextStart, javadocTextEnd = -1;
62
	protected int javadocTextStart, javadocTextEnd = -1;
63
	protected int firstTagPosition;
63
	protected int firstTagPosition;
64
	protected int index, lineEnd;
64
	protected int index, lineEnd;
65
	protected int tokenPreviousPosition, lastIdentifierEndPosition, starPosition, spacePosition;
65
	protected int tokenPreviousPosition, lastIdentifierEndPosition, starPosition;
66
	protected int textStart, memberStart;
66
	protected int textStart, memberStart;
67
	protected int tagSourceStart, tagSourceEnd;
67
	protected int tagSourceStart, tagSourceEnd;
68
	protected int inlineTagStart;
68
	protected int inlineTagStart;
Lines 133-139 Link Here
133
			this.deprecated = false;
133
			this.deprecated = false;
134
			this.lastLinePtr = getLineNumber(javadocEnd);
134
			this.lastLinePtr = getLineNumber(javadocEnd);
135
			this.textStart = -1;
135
			this.textStart = -1;
136
			this.spacePosition = -1;
137
			char previousChar = 0;
136
			char previousChar = 0;
138
			int invalidTagLineEnd = -1;
137
			int invalidTagLineEnd = -1;
139
			int invalidInlineTagLineEnd = -1;
138
			int invalidInlineTagLineEnd = -1;
Lines 163-171 Link Here
163
				this.javadocTextStart = this.index;
162
				this.javadocTextStart = this.index;
164
			}
163
			}
165
			this.lineEnd = (this.linePtr == this.lastLinePtr) ? this.javadocEnd: this.scanner.getLineEnd(this.linePtr) - 1;
164
			this.lineEnd = (this.linePtr == this.lastLinePtr) ? this.javadocEnd: this.scanner.getLineEnd(this.linePtr) - 1;
165
			this.javadocTextEnd = this.javadocEnd - 2; // supposed text end, it will be refined later...
166
			
166
			
167
			// Loop on each comment character
167
			// Loop on each comment character
168
			int textEndPosition = -1;
168
			while (!abort && this.index < this.javadocEnd) {
169
			while (!abort && this.index < this.javadocEnd) {
170
171
				// Store previous position and char
169
				previousPosition = this.index;
172
				previousPosition = this.index;
170
				previousChar = nextCharacter;
173
				previousChar = nextCharacter;
171
				
174
				
Lines 206-215 Link Here
206
									this.sourceParser.problemReporter().javadocUnterminatedInlineTag(this.inlineTagStart, end);
209
									this.sourceParser.problemReporter().javadocUnterminatedInlineTag(this.inlineTagStart, end);
207
								}
210
								}
208
								validComment = false;
211
								validComment = false;
209
								int textEndPosition = previousPosition;
210
								if (isFormatterParser && ScannerHelper.isWhitespace(previousChar)) {
211
									textEndPosition = this.spacePosition;
212
								}
213
								if (this.textStart != -1 && this.textStart < textEndPosition) {
212
								if (this.textStart != -1 && this.textStart < textEndPosition) {
214
									if (pushText) pushText(this.textStart, textEndPosition);
213
									if (pushText) pushText(this.textStart, textEndPosition);
215
								}
214
								}
Lines 219-228 Link Here
219
							}
218
							}
220
							if (previousChar == '{') {
219
							if (previousChar == '{') {
221
								if (this.textStart != -1) {
220
								if (this.textStart != -1) {
222
									int textEndPosition = this.inlineTagStart;
223
									if (isFormatterParser && this.spacePosition == (this.inlineTagStart-1)) {
224
										textEndPosition = this.spacePosition;
225
									}
226
									if (this.textStart < textEndPosition) {
221
									if (this.textStart < textEndPosition) {
227
										if (pushText) pushText(this.textStart, textEndPosition);
222
										if (pushText) pushText(this.textStart, textEndPosition);
228
									}
223
									}
Lines 230-240 Link Here
230
								this.inlineTagStarted = true;
225
								this.inlineTagStarted = true;
231
								invalidInlineTagLineEnd = this.lineEnd;
226
								invalidInlineTagLineEnd = this.lineEnd;
232
							} else if (this.textStart != -1 && this.textStart < invalidTagLineEnd) {
227
							} else if (this.textStart != -1 && this.textStart < invalidTagLineEnd) {
233
								int textEndPosition = invalidTagLineEnd;
228
								if (pushText) pushText(this.textStart, invalidTagLineEnd);
234
								if (isFormatterParser && ScannerHelper.isWhitespace(previousChar)) {
235
									textEndPosition = this.spacePosition;
236
								}
237
								if (pushText) pushText(this.textStart, textEndPosition);
238
							}
229
							}
239
							this.scanner.resetTo(this.index, this.javadocEnd);
230
							this.scanner.resetTo(this.index, this.javadocEnd);
240
							this.currentTokenType = -1; // flush token cache at line begin
231
							this.currentTokenType = -1; // flush token cache at line begin
Lines 250-276 Link Here
250
									}
241
									}
251
									this.textStart = this.tagSourceEnd+1;
242
									this.textStart = this.tagSourceEnd+1;
252
									invalidTagLineEnd  = this.lineEnd;
243
									invalidTagLineEnd  = this.lineEnd;
244
									textEndPosition = this.index;
253
								}
245
								}
254
							} catch (InvalidInputException e) {
246
							} catch (InvalidInputException e) {
255
								consumeToken();
247
								consumeToken();
256
							}
248
							}
257
						} else if (verifText && this.tagValue == TAG_RETURN_VALUE && this.returnStatement != null) {
249
						} else {
258
							refreshReturnStatement();
250
							textEndPosition = this.index;
259
						} else if (isFormatterParser) {
251
							if (verifText && this.tagValue == TAG_RETURN_VALUE && this.returnStatement != null) {
260
							if (this.textStart == -1) this.textStart = previousPosition;
252
								refreshReturnStatement();
253
							} else if (isFormatterParser) {
254
								if (this.textStart == -1) this.textStart = previousPosition;
255
							}
261
						}
256
						}
262
						this.lineStarted = true;
257
						this.lineStarted = true;
263
						break;
258
						break;
264
					case '\r':
259
					case '\r':
265
					case '\n':
260
					case '\n':
266
						if (this.lineStarted) {
261
						if (this.lineStarted) {
267
							int textEndPosition = previousPosition;
262
							if (isFormatterParser && !ScannerHelper.isWhitespace(previousChar)) {
268
							if (isFormatterParser) {
263
								textEndPosition = previousPosition;
269
								if (ScannerHelper.isWhitespace(previousChar)) {
270
									textEndPosition = this.spacePosition;
271
								} else {
272
									this.spacePosition = previousPosition;
273
								}
274
							}
264
							}
275
							if (this.textStart != -1 && this.textStart < textEndPosition) {
265
							if (this.textStart != -1 && this.textStart < textEndPosition) {
276
								if (pushText) pushText(this.textStart, textEndPosition);
266
								if (pushText) pushText(this.textStart, textEndPosition);
Lines 287-296 Link Here
287
						}
277
						}
288
						if (this.inlineTagStarted) {
278
						if (this.inlineTagStarted) {
289
							if (pushText) {
279
							if (pushText) {
290
								int textEndPosition = previousPosition;
291
								if (isFormatterParser && ScannerHelper.isWhitespace(previousChar)) {
292
									textEndPosition = this.spacePosition;
293
								}
294
								if (this.lineStarted && this.textStart != -1 && this.textStart < textEndPosition) {
280
								if (this.lineStarted && this.textStart != -1 && this.textStart < textEndPosition) {
295
									pushText(this.textStart, textEndPosition);
281
									pushText(this.textStart, textEndPosition);
296
								}
282
								}
Lines 304-309 Link Here
304
							}
290
							}
305
						}
291
						}
306
						this.lineStarted = true;
292
						this.lineStarted = true;
293
						textEndPosition = this.index;
307
						break;
294
						break;
308
					case '{' :
295
					case '{' :
309
						if (verifText && this.tagValue == TAG_RETURN_VALUE && this.returnStatement != null) {
296
						if (verifText && this.tagValue == TAG_RETURN_VALUE && this.returnStatement != null) {
Lines 318-332 Link Here
318
								this.sourceParser.problemReporter().javadocUnterminatedInlineTag(this.inlineTagStart, end);
305
								this.sourceParser.problemReporter().javadocUnterminatedInlineTag(this.inlineTagStart, end);
319
							}
306
							}
320
							if (pushText) {
307
							if (pushText) {
321
								int textEndPosition = previousPosition;
322
								if (isFormatterParser && ScannerHelper.isWhitespace(previousChar)) {
323
									textEndPosition = this.spacePosition;
324
								}
325
								if (this.lineStarted && this.textStart != -1 && this.textStart < textEndPosition) {
308
								if (this.lineStarted && this.textStart != -1 && this.textStart < textEndPosition) {
326
									pushText(this.textStart, textEndPosition);
309
									pushText(this.textStart, textEndPosition);
327
								}
310
								}
328
								refreshInlineTagPosition(textEndPosition);
311
								refreshInlineTagPosition(textEndPosition);
329
							}
312
							}
313
							textEndPosition = this.index;
314
						} else if (peekChar() != '@') {
315
							textEndPosition = this.index;
330
						}
316
						}
331
						if (!this.lineStarted) {
317
						if (!this.lineStarted) {
332
							this.textStart = previousPosition;
318
							this.textStart = previousPosition;
Lines 352-360 Link Here
352
					case '\u000c' :	/* FORM FEED               */
338
					case '\u000c' :	/* FORM FEED               */
353
					case ' ' :			/* SPACE                   */
339
					case ' ' :			/* SPACE                   */
354
					case '\t' :			/* HORIZONTAL TABULATION   */
340
					case '\t' :			/* HORIZONTAL TABULATION   */
355
						// Store first space position while formatting
341
						// Do not include trailing spaces in text while formatting
356
						if (isFormatterParser && !ScannerHelper.isWhitespace(previousChar)) {
342
						if (isFormatterParser) {
357
							this.spacePosition = previousPosition;
343
							if (!ScannerHelper.isWhitespace(previousChar)) {
344
								textEndPosition = previousPosition;
345
							}
346
						} else if (this.lineStarted) {
347
							textEndPosition = this.index;
358
						}
348
						}
359
						break;
349
						break;
360
					case '/':
350
					case '/':
Lines 368-375 Link Here
368
							// html tags are meaningful for formatter parser
358
							// html tags are meaningful for formatter parser
369
							int initialIndex = this.index;
359
							int initialIndex = this.index;
370
							this.scanner.resetTo(this.index, this.javadocEnd);
360
							this.scanner.resetTo(this.index, this.javadocEnd);
371
							int endTextPosition = ScannerHelper.isWhitespace(previousChar) ? this.spacePosition : previousPosition;
361
							if (!ScannerHelper.isWhitespace(previousChar)) {
372
							if (parseHtmlTag(previousPosition, endTextPosition)) {
362
								textEndPosition = previousPosition;
363
							}
364
							if (parseHtmlTag(previousPosition, textEndPosition)) {
373
								break;
365
								break;
374
							}
366
							}
375
							if (this.abort) return false;
367
							if (this.abort) return false;
Lines 384-389 Link Here
384
							this.textStart = previousPosition;
376
							this.textStart = previousPosition;
385
						}
377
						}
386
						this.lineStarted = true;
378
						this.lineStarted = true;
379
						textEndPosition = this.index;
387
						break;
380
						break;
388
				}
381
				}
389
			}
382
			}
Lines 398-415 Link Here
398
					this.sourceParser.problemReporter().javadocUnterminatedInlineTag(this.inlineTagStart, end);
391
					this.sourceParser.problemReporter().javadocUnterminatedInlineTag(this.inlineTagStart, end);
399
				}
392
				}
400
				if (pushText) {
393
				if (pushText) {
401
					int textEndPosition = this.javadocTextEnd;
402
					if (isFormatterParser && ScannerHelper.isWhitespace(previousChar)) {
403
						textEndPosition = this.spacePosition;
404
					}
405
					if (this.lineStarted && this.textStart != -1 && this.textStart < textEndPosition) {
394
					if (this.lineStarted && this.textStart != -1 && this.textStart < textEndPosition) {
406
						pushText(this.textStart, textEndPosition);
395
						pushText(this.textStart, textEndPosition);
407
					}
396
					}
408
					refreshInlineTagPosition(textEndPosition);
397
					refreshInlineTagPosition(textEndPosition);
409
				}
398
				}
410
				this.inlineTagStarted = false;
399
				this.inlineTagStarted = false;
411
			} else if (pushText && this.lineStarted && this.textStart != -1 && this.textStart <= this.javadocTextEnd) {
400
			} else if (pushText && this.lineStarted && this.textStart != -1 && this.textStart <= textEndPosition) {
412
				pushText(this.textStart, this.starPosition);
401
				pushText(this.textStart, textEndPosition);
413
			}
402
			}
414
			updateDocComment();
403
			updateDocComment();
415
		} catch (Exception ex) {
404
		} catch (Exception ex) {
Lines 1539-1551 Link Here
1539
	 * Note that end of comment may be preceding by several contiguous '*' chars.
1528
	 * Note that end of comment may be preceding by several contiguous '*' chars.
1540
	 */
1529
	 */
1541
	protected boolean verifyEndLine(int textPosition) {
1530
	protected boolean verifyEndLine(int textPosition) {
1542
		boolean isDomParser = (this.kind & DOM_PARSER) != 0;
1531
		boolean domParser = (this.kind & DOM_PARSER) != 0;
1543
		boolean isFormatterParser = (this.kind & FORMATTER_COMMENT_PARSER) != 0;
1544
		// Special case for inline tag
1532
		// Special case for inline tag
1545
		if (this.inlineTagStarted) {
1533
		if (this.inlineTagStarted) {
1546
			// expecting closing brace
1534
			// expecting closing brace
1547
			if (peekChar() == '}') {
1535
			if (peekChar() == '}') {
1548
				if (isDomParser || isFormatterParser) {
1536
				if (domParser) {
1549
					createTag();
1537
					createTag();
1550
					pushText(textPosition, this.starPosition);
1538
					pushText(textPosition, this.starPosition);
1551
				}
1539
				}
Lines 1556-1585 Link Here
1556
		
1544
		
1557
		int startPosition = this.index;
1545
		int startPosition = this.index;
1558
		int previousPosition = this.index;
1546
		int previousPosition = this.index;
1559
		int spacePos = this.index;
1560
		this.starPosition = -1;
1547
		this.starPosition = -1;
1561
		char ch = readChar();
1548
		char ch = readChar();
1562
		char previousChar = ch;
1563
		nextChar: while (true) {
1549
		nextChar: while (true) {
1564
			switch (ch) {
1550
			switch (ch) {
1565
				case '\r':
1551
				case '\r':
1566
				case '\n':
1552
				case '\n':
1567
					if (isDomParser || isFormatterParser) {
1553
					if (domParser) {
1568
						createTag();
1554
						createTag();
1569
						int textEndPosition = previousPosition;
1555
						pushText(textPosition, previousPosition);
1570
						if (isFormatterParser && ScannerHelper.isWhitespace(previousChar)) {
1571
							textEndPosition = spacePos;
1572
						}
1573
						pushText(textPosition, textEndPosition);
1574
					}
1556
					}
1575
					this.index = previousPosition;
1557
					this.index = previousPosition;
1576
					return true;
1558
					return true;
1577
				case '\u000c' :	/* FORM FEED               */
1559
				case '\u000c' :	/* FORM FEED               */
1578
				case ' ' :			/* SPACE                   */
1560
				case ' ' :			/* SPACE                   */
1579
				case '\t' :			/* HORIZONTAL TABULATION   */
1561
				case '\t' :			/* HORIZONTAL TABULATION   */
1580
					if (isFormatterParser && previousChar != ch && !ScannerHelper.isWhitespace(previousChar)) {
1581
						this.spacePosition = previousPosition;
1582
					}
1583
					if (this.starPosition >= 0) break nextChar;
1562
					if (this.starPosition >= 0) break nextChar;
1584
					break;
1563
					break;
1585
				case '*':
1564
				case '*':
Lines 1587-1599 Link Here
1587
					break;
1566
					break;
1588
				case '/':
1567
				case '/':
1589
					if (this.starPosition >= textPosition) {
1568
					if (this.starPosition >= textPosition) {
1590
						if (isDomParser || isFormatterParser) {
1569
						if (domParser) {
1591
							createTag();
1570
							createTag();
1592
							int textEndPosition = this.starPosition;
1571
							pushText(textPosition, this.starPosition);
1593
							if (isFormatterParser && ScannerHelper.isWhitespace(previousChar)) {
1594
								textEndPosition = this.spacePosition;
1595
							}
1596
							pushText(textPosition, textEndPosition);
1597
						}
1572
						}
1598
						return true;
1573
						return true;
1599
					}
1574
					}
Lines 1603-1609 Link Here
1603
				
1578
				
1604
			}
1579
			}
1605
			previousPosition = this.index;
1580
			previousPosition = this.index;
1606
			previousChar = ch;
1607
			ch = readChar();
1581
			ch = readChar();
1608
		}
1582
		}
1609
		this.index = startPosition;
1583
		this.index = startPosition;

Return to bug 236230