diff options
Diffstat (limited to 'org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java')
-rw-r--r-- | org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java | 592 |
1 files changed, 338 insertions, 254 deletions
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java index 02d2fd161..6d7fd2289 100644 --- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java +++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/Scribe.java @@ -111,6 +111,7 @@ public class Scribe implements IJavaDocTagConstants { /** disabling */ boolean editsEnabled; boolean useTags; + int tagsKind; /* Comments formatting */ private static final int INCLUDE_BLOCK_COMMENTS = CodeFormatter.F_INCLUDE_COMMENTS | CodeFormatter.K_MULTI_LINE_COMMENT; @@ -228,26 +229,12 @@ public class Scribe implements IJavaDocTagConstants { // the offset of the region is inside a comment => restart the region from the comment start adaptedOffset = this.commentPositions[index][0]; if (adaptedOffset >= 0) { - // adapt only javadoc or block commments. Since fix for bug + // adapt only javadoc or block comments. Since fix for bug // https://bugs.eclipse.org/bugs/show_bug.cgi?id=238210 // edits in line comments only concerns whitespaces hence can be // treated as edits in code adaptedLength = length + offset - adaptedOffset; commentIndex = index; - // include also the indentation edit just before the comment if any - for (int j=0; j<this.editsIndex; j++) { - int editOffset = this.edits[j].offset; - int editEnd = editOffset + this.edits[j].length; - if (editEnd == adaptedOffset) { - if (j > 0 && this.edits[j].replacement.trim().length() == 0) { - adaptedLength += adaptedOffset - this.edits[j].offset; - adaptedOffset = editOffset; - break; - } - } else if (editEnd > adaptedOffset) { - break; - } - } } } index = getCommentIndex(commentIndex, offset+length-1); @@ -308,6 +295,14 @@ public class Scribe implements IJavaDocTagConstants { currentEdit = index; } } + + // Set invalid all edits outside the region + if (currentEdit != -1) { + int length = sortedEdits.length; + for (int e=currentEdit; e<length; e++) { + sortedEdits[e].offset = -1; + } + } } /* @@ -325,12 +320,12 @@ public class Scribe implements IJavaDocTagConstants { * region. */ private int adaptEdit(OptimizedReplaceEdit[] sortedEdits, int start, int regionStart, int regionEnd) { - int bottom = start==-1?0:start, top = sortedEdits.length - 1; + int initialStart = start==-1 ? 0 : start; + int bottom = initialStart, top = sortedEdits.length - 1; int topEnd = top; int i = 0; OptimizedReplaceEdit edit = null; int overlapIndex = -1; - int linesOutside= -1; // Look for an edit overlapping the region start while (bottom <= top) { @@ -338,28 +333,37 @@ public class Scribe implements IJavaDocTagConstants { edit = sortedEdits[i]; int editStart = edit.offset; int editEnd = editStart + edit.length; - if (regionStart < editStart) { // the edit starts after the region's start => no possible overlap of region's start + if (editStart > regionStart) { // the edit starts after the region's start => no possible overlap of region's start top = i-1; - if (regionEnd < editStart) { // the edit starts after the region's end => no possible overlap of region's end + if (editStart > regionEnd) { // the edit starts after the region's end => no possible overlap of region's end topEnd = top; } } else { - if (regionStart >= editEnd) { // the edit ends before the region's start => no possible overlap of region's start + if (editEnd < regionStart) { // the edit ends before the region's start => no possible overlap of region's start bottom = i+1; } else { // Count the lines of the edit which are outside the region - linesOutside = 0; + int linesOutside = 0; + StringBuffer spacesOutside = new StringBuffer(); this.scanner.resetTo(editStart, editEnd-1); - while (!this.scanner.atEnd()) { - boolean before = this.scanner.currentPosition < regionStart; - char ch = (char) this.scanner.getNextChar(); - if (ch == '\n' ) { - if (before) linesOutside++; - } - } + while (this.scanner.currentPosition < regionStart && !this.scanner.atEnd()) { + char ch = (char) this.scanner.getNextChar(); + switch (ch) { + case '\n': + linesOutside++; + spacesOutside.setLength(0); + break; + case '\r': + break; + default: + spacesOutside.append(ch); + break; + } + } // Restart the edit at the beginning of the line where the region start edit.offset = regionStart; + int editLength = edit.length; edit.length -= edit.offset - editStart; // Cut replacement string if necessary @@ -372,36 +376,64 @@ public class Scribe implements IJavaDocTagConstants { if (edit.replacement.charAt(idx) == '\n') linesReplaced++; } - // As the edit starts outside the region, remove first lines from edit string if any - if (linesReplaced > 0) { - int linesCount = linesOutside >= linesReplaced ? linesReplaced : linesOutside; - if (linesCount > 0) { - int idx=0; - loop: while (idx < length) { - char ch = edit.replacement.charAt(idx); - switch (ch) { - case '\n': - linesCount--; - if (linesCount == 0) { - idx++; - break loop; - } - break; - case '\r': - case ' ': - case '\t': - break; - default: - break loop; - } - idx++; - } - if (idx >= length) { - edit.replacement = ""; //$NON-NLS-1$ - } else { - edit.replacement = edit.replacement.substring(idx); - } - } + // If the edit was a replacement but become an insertion due to the length reduction + // and if the edit finishes just before the region starts and if there's no line to replace + // then there's no replacement to do... + if (editLength > 0 && edit.length == 0 && editEnd == regionStart && linesReplaced == 0 && linesOutside== 0) { + edit.offset = -1; + } else { + + // As the edit starts outside the region, remove first lines from edit string if any + if (linesReplaced > 0) { + int linesCount = linesOutside >= linesReplaced ? linesReplaced : linesOutside; + if (linesCount > 0) { + int idx = 0; + loop: while (idx < length) { + char ch = edit.replacement.charAt(idx); + switch (ch) { + case '\n': + linesCount--; + if (linesCount == 0) { + idx++; + break loop; + } + break; + case '\r': + case ' ': + case '\t': + break; + default: + break loop; + } + idx++; + } + // Compare spaces outside the region and the beginning + // of the replacement string to remove the common part + int spacesOutsideLength = spacesOutside.length(); + int replacementStart = idx; + for (int o=0, r=0; o < spacesOutsideLength && r<(length-idx); o++) { + char rch = edit.replacement.charAt(idx + r); + char och = spacesOutside.charAt(o); + if (rch == och) { + replacementStart++; + r++; + } else if (rch == '\t' && (this.tabLength > 0 && och == ' ')) { + if ((o+1)%this.tabLength == 0) { + replacementStart++; + r++; + } + } else { + break; + } + } + // Update the replacement string + if (replacementStart >= length) { + edit.offset = -1; + } else { + edit.replacement = edit.replacement.substring(replacementStart); + } + } + } } } overlapIndex = i; @@ -409,6 +441,7 @@ public class Scribe implements IJavaDocTagConstants { } } } + int validIndex = (overlapIndex != -1) ? overlapIndex : bottom; // Look for an edit overlapping the region end if (overlapIndex != -1) bottom = overlapIndex; @@ -417,53 +450,87 @@ public class Scribe implements IJavaDocTagConstants { edit = sortedEdits[i]; int editStart = edit.offset; int editEnd = editStart + edit.length; - if (regionEnd < editStart) { // the edit starts after the region's end => no possible overlap of region's end + if (regionEnd < editStart) { // the edit starts after the region's end => no possible overlap of region's end topEnd = i-1; - } else { - if (regionEnd >= editEnd) { // the edit ends before the region's end => no possible overlap of region's end - bottom = i+1; - } else { - // Count the lines of the edit which are outside the region - linesOutside = 0; - this.scanner.resetTo(editStart, editEnd-1); - while (!this.scanner.atEnd()) { - boolean after = this.scanner.currentPosition >= regionEnd; - char ch = (char) this.scanner.getNextChar(); - if (ch == '\n' ) { - if (after) linesOutside++; - } - } + } else if (regionEnd == editStart) { // special case when the edit starts just after the region's end... + // ...we got the last index of the edit inside the region + topEnd = i - 1; + // this last edit is valid only if it's an insertion and if it has indentation + if (edit.length == 0) { + int nrLength = 0; + int rLength = edit.replacement.length(); + int ch = edit.replacement.charAt(nrLength); + loop: while (nrLength < rLength) { + switch (ch) { + case ' ': + case '\t': + nrLength++; + break; + default: + break loop; + } + } + if (nrLength > 0) { + topEnd++; + if (nrLength < rLength) { + edit.replacement = edit.replacement.substring(0, nrLength); + } + } + } + break; + } else if (editEnd <= regionEnd) { // the edit ends before the region's end => no possible overlap of region's end + bottom = i+1; + } else { + // Count the lines of the edit which are outside the region + int linesOutside = 0; + this.scanner.resetTo(editStart, editEnd-1); + while (!this.scanner.atEnd()) { + boolean after = this.scanner.currentPosition >= regionEnd; + char ch = (char) this.scanner.getNextChar(); + if (ch == '\n' ) { + if (after) linesOutside++; + } + } - // Cut replacement string if necessary - int length = edit.replacement.length(); - if (length > 0) { + // Cut replacement string if necessary + int length = edit.replacement.length(); + if (length > 0) { - // Count the lines in replacement string - int linesReplaced = 0; - for (int idx=0; idx < length; idx++) { - if (edit.replacement.charAt(idx) == '\n') linesReplaced++; - } + // Count the lines in replacement string + int linesReplaced = 0; + for (int idx=0; idx < length; idx++) { + if (edit.replacement.charAt(idx) == '\n') linesReplaced++; + } - // Set the replacement string to the number of missing new lines - // As the end of the edit is out of the region, the possible trailing - // indentation should not be added... - if (linesReplaced == 0) { + // Set the replacement string to the number of missing new lines + // As the end of the edit is out of the region, the possible trailing + // indentation should not be added... + if (linesReplaced == 0) { + edit.replacement = ""; //$NON-NLS-1$ + } else { + int linesCount = linesReplaced > linesOutside ? linesReplaced - linesOutside : 0; + if (linesCount == 0) { edit.replacement = ""; //$NON-NLS-1$ } else { - int linesCount = linesReplaced > linesOutside ? linesReplaced - linesOutside : 0; - if (linesCount == 0) { - edit.replacement = ""; //$NON-NLS-1$ - } else { - edit.replacement = getNewLineString(linesCount); - } + edit.replacement = getNewLineString(linesCount); } } - edit.length -= editEnd - regionEnd; - return i; } + edit.length = regionEnd - editStart; + + // We got the last edit of the regions, give up + topEnd = i; + break; } } - return overlapIndex; + + // Set invalid all edits outside the region + for (int e=initialStart; e<validIndex; e++) { + sortedEdits[e].offset = -1; + } + + // Return the index of next edit to look at + return topEnd+1; } private final void addDeleteEdit(int start, int end) { @@ -821,24 +888,6 @@ public class Scribe implements IJavaDocTagConstants { return -1; } - private IRegion getCoveringAdaptedRegion(int offset, int end) { - int index = getIndexOfAdaptedRegionAt(offset); - - if (index < 0) { - index = -(index + 1); - index--; - if (index < 0) { - return null; - } - } - - IRegion region = this.adaptedRegions[index]; - if ((region.getOffset() <= offset) && (end <= region.getOffset() + region.getLength() - 1)) { - return region; - } - return null; - } - private int getCurrentCommentIndentation(int start) { int linePtr = -Arrays.binarySearch(this.lineEnds, start); int indentation = 0; @@ -884,6 +933,7 @@ public class Scribe implements IJavaDocTagConstants { } int getCurrentIndentation(char[] whitespaces, int offset) { + if (whitespaces == null) return offset; int length = whitespaces.length; if (this.tabLength == 0) return length; int indentation = offset; @@ -1012,24 +1062,6 @@ public class Scribe implements IJavaDocTagConstants { return emptyLines; } - private int getIndexOfAdaptedRegionAt(int offset) { - if (this.adaptedRegions.length == 1) { - int offset2 = this.adaptedRegions[0].getOffset(); - if (offset2 == offset) { - return 0; - } - return offset2 < offset ? -2 : -1; - } - return Arrays.binarySearch(this.adaptedRegions, new Region(offset, 0), new Comparator() { - public int compare(Object o1, Object o2) { - int r1Offset = ((IRegion)o1).getOffset(); - int r2Offset = ((IRegion)o2).getOffset(); - - return r1Offset - r2Offset; - } - }); - } - public OptimizedReplaceEdit getLastEdit() { if (this.editsIndex > 0) { return this.edits[this.editsIndex - 1]; @@ -1182,8 +1214,10 @@ public class Scribe implements IJavaDocTagConstants { linePtr = -linePtr - 1; } int i = getLineEnd(linePtr)+1; - while (this.scanner.source[i] != '\r') { - System.out.print(this.scanner.source[i++]); + char[] source = this.scanner.source; + int sourceLength = source.length; + while (i < sourceLength && source[i] != '\r') { + System.out.print(source[i++]); } System.out.println(); System.out.println(" - indentation level = "+this.indentationLevel); //$NON-NLS-1$ @@ -1210,15 +1244,6 @@ public class Scribe implements IJavaDocTagConstants { return getNewLine(); } - private IRegion getAdaptedRegionAt(int offset) { - int index = getIndexOfAdaptedRegionAt(offset); - if (index < 0) { - return null; - } - - return this.adaptedRegions[index]; - } - public TextEdit getRootEdit() { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=208541 adaptRegions(); @@ -1251,14 +1276,16 @@ public class Scribe implements IJavaDocTagConstants { } for (int i= 0, max = this.editsIndex; i < max; i++) { OptimizedReplaceEdit currentEdit = this.edits[i]; - if (isValidEdit(currentEdit)) { - try { - edit.addChild(new ReplaceEdit(currentEdit.offset, currentEdit.length, currentEdit.replacement)); - } - catch (MalformedTreeException ex) { - // log exception in case of error - CommentFormatterUtil.log(ex); - throw ex; + if (currentEdit.offset >= 0 && currentEdit.offset <= this.scannerEndPosition) { + if (currentEdit.length == 0 || (currentEdit.offset != this.scannerEndPosition && isMeaningfulEdit(currentEdit))) { + try { + edit.addChild(new ReplaceEdit(currentEdit.offset, currentEdit.length, currentEdit.replacement)); + } + catch (MalformedTreeException ex) { + // log exception in case of error + CommentFormatterUtil.log(ex); + throw ex; + } } } } @@ -1425,6 +1452,7 @@ public class Scribe implements IJavaDocTagConstants { private void initializeScanner(long sourceLevel, DefaultCodeFormatterOptions preferences) { this.useTags = preferences.use_tags; + this.tagsKind = 0; char[][] taskTags = null; if (this.useTags) { this.disablingTag = preferences.disabling_tag; @@ -1439,6 +1467,23 @@ public class Scribe implements IJavaDocTagConstants { taskTags = new char[][] { this.disablingTag, this.enablingTag }; } } + if (taskTags != null) { + loop: for (int i=0,length=taskTags.length; i<length; i++) { + if (taskTags[i].length > 2 && taskTags[i][0] == '/') { + switch (taskTags[i][1]) { + case '/': + this.tagsKind = TerminalTokens.TokenNameCOMMENT_LINE; + break loop; + case '*': + if (taskTags[i][2] != '*') { + this.tagsKind = TerminalTokens.TokenNameCOMMENT_BLOCK; + break loop; + } + break; + } + } + } + } this.scanner = new Scanner(true, true, false/*nls*/, sourceLevel/*sourceLevel*/, taskTags, null/*taskPriorities*/, true/*taskCaseSensitive*/); this.editsEnabled = true; } @@ -1462,71 +1507,19 @@ public class Scribe implements IJavaDocTagConstants { return previousLineEnd != -1 && previousLineEnd == start - 1; } - private boolean isValidEdit(OptimizedReplaceEdit edit) { + private boolean isMeaningfulEdit(OptimizedReplaceEdit edit) { final int editLength= edit.length; final int editReplacementLength= edit.replacement.length(); final int editOffset= edit.offset; - if (editLength != 0) { - - IRegion covering = getCoveringAdaptedRegion(editOffset, (editOffset + editLength - 1)); - if (covering != null) { - if (editReplacementLength != 0 && editLength == editReplacementLength) { - for (int i = editOffset, max = editOffset + editLength; i < max; i++) { - if (this.scanner.source[i] != edit.replacement.charAt(i - editOffset)) { - return true; - } - } - return false; - } - return true; - } - - IRegion starting = getAdaptedRegionAt(editOffset + editLength); - if (starting != null) { - int i = editOffset; - for (int max = editOffset + editLength; i < max; i++) { - int replacementStringIndex = i - editOffset; - if (replacementStringIndex >= editReplacementLength || this.scanner.source[i] != edit.replacement.charAt(replacementStringIndex)) { - break; - } - } - if (i - editOffset != editReplacementLength && i != editOffset + editLength - 1) { - edit.offset = starting.getOffset(); - edit.length = 0; - edit.replacement = edit.replacement.substring(i - editOffset); + if (editReplacementLength != 0 && editLength == editReplacementLength) { + for (int i = editOffset, max = editOffset + editLength; i < max; i++) { + if (this.scanner.source[i] != edit.replacement.charAt(i - editOffset)) { return true; } } - return false; } - - IRegion covering = getCoveringAdaptedRegion(editOffset, editOffset); - if (covering != null) { - return true; - } - - if (editOffset == this.scannerEndPosition) { - int index = Arrays.binarySearch( - this.adaptedRegions, - new Region(editOffset, 0), - new Comparator() { - public int compare(Object o1, Object o2) { - IRegion r1 = (IRegion)o1; - IRegion r2 = (IRegion)o2; - - int r1End = r1.getOffset() + r1.getLength(); - int r2End = r2.getOffset() + r2.getLength(); - - return r1End - r2End; - } - }); - if (index < 0) { - return false; - } - return true; - } - return false; + return true; } private void preserveEmptyLines(int count, int insertPosition) { @@ -2372,13 +2365,12 @@ public class Scribe implements IJavaDocTagConstants { boolean hasLineComment = false; boolean hasWhitespaces = false; int lines = 0; - int previousFoundTaskCount = this.scanner.foundTaskCount; while ((this.currentToken = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { int foundTaskCount = this.scanner.foundTaskCount; + int tokenStartPosition = this.scanner.getCurrentTokenStartPosition(); switch(this.currentToken) { case TerminalTokens.TokenNameWHITESPACE : char[] whiteSpaces = this.scanner.getCurrentTokenSource(); - int whitespacesStartPosition = this.scanner.getCurrentTokenStartPosition(); int whitespacesEndPosition = this.scanner.getCurrentTokenEndPosition(); lines = 0; for (int i = 0, max = whiteSpaces.length; i < max; i++) { @@ -2452,7 +2444,7 @@ public class Scribe implements IJavaDocTagConstants { // if a line comment is consumed, no other comment can be on the same line after if (hasLineComment) { if (lines >= 1) { - currentTokenStartPosition = whitespacesStartPosition; + currentTokenStartPosition = tokenStartPosition; preserveEmptyLines(lines, currentTokenStartPosition); addDeleteEdit(currentTokenStartPosition, whitespacesEndPosition); this.scanner.resetTo(this.scanner.currentPosition, this.scannerEndPosition - 1); @@ -2464,7 +2456,7 @@ public class Scribe implements IJavaDocTagConstants { // if one or several new lines are consumed, following comments cannot be considered as trailing ones if (lines >= 1) { if (hasComment) { - this.printNewLine(whitespacesStartPosition); + this.printNewLine(tokenStartPosition); } this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1); return; @@ -2472,40 +2464,49 @@ public class Scribe implements IJavaDocTagConstants { // delete consumed white spaces hasWhitespaces = true; currentTokenStartPosition = this.scanner.currentPosition; - addDeleteEdit(whitespacesStartPosition, whitespacesEndPosition); + addDeleteEdit(tokenStartPosition, whitespacesEndPosition); } else { if (lines == 0) { hasWhitespaces = true; - addDeleteEdit(whitespacesStartPosition, whitespacesEndPosition); + addDeleteEdit(tokenStartPosition, whitespacesEndPosition); } else if (hasLineComment) { - currentTokenStartPosition = whitespacesStartPosition; + currentTokenStartPosition = tokenStartPosition; preserveEmptyLines(lines, currentTokenStartPosition); addDeleteEdit(currentTokenStartPosition, whitespacesEndPosition); } else if (hasComment) { if (lines == 1) { - this.printNewLine(whitespacesStartPosition); + this.printNewLine(tokenStartPosition); } else { - preserveEmptyLines(lines - 1, whitespacesStartPosition); + preserveEmptyLines(lines - 1, tokenStartPosition); } - addDeleteEdit(whitespacesStartPosition, whitespacesEndPosition); + addDeleteEdit(tokenStartPosition, whitespacesEndPosition); } else if (lines != 0 && (!this.formatter.preferences.join_wrapped_lines || this.formatter.preferences.number_of_empty_lines_to_preserve != 0 || this.blank_lines_between_import_groups > 0)) { - addReplaceEdit(whitespacesStartPosition, whitespacesEndPosition, getPreserveEmptyLines(lines-1)); + addReplaceEdit(tokenStartPosition, whitespacesEndPosition, getPreserveEmptyLines(lines-1)); } else { - addDeleteEdit(whitespacesStartPosition, whitespacesEndPosition); + addDeleteEdit(tokenStartPosition, whitespacesEndPosition); } } currentTokenStartPosition = this.scanner.currentPosition; break; case TerminalTokens.TokenNameCOMMENT_LINE : - if (this.useTags && this.editsEnabled && foundTaskCount > previousFoundTaskCount) { - setEditsEnabled(foundTaskCount, previousFoundTaskCount); - if (!this.editsEnabled && this.editsIndex > 1) { - OptimizedReplaceEdit currentEdit = this.edits[this.editsIndex-1]; - if (this.scanner.startPosition == currentEdit.offset+currentEdit.length) { - printNewLinesBeforeDisablingComment(); + if (this.useTags && this.editsEnabled) { + boolean turnOff = false; + if (foundTaskCount > 0) { + setEditsEnabled(foundTaskCount); + turnOff = true; + } else if (this.tagsKind == this.currentToken + && CharOperation.fragmentEquals(this.disablingTag, this.scanner.source, tokenStartPosition, true)) { + this.editsEnabled = false; + turnOff = true; + } + if (turnOff) { + if (!this.editsEnabled && this.editsIndex > 1) { + OptimizedReplaceEdit currentEdit = this.edits[this.editsIndex-1]; + if (this.scanner.startPosition == currentEdit.offset+currentEdit.length) { + printNewLinesBeforeDisablingComment(); + } } } - previousFoundTaskCount = foundTaskCount; } if (rejectLineComment) break; if (lines >= 1) { @@ -2522,20 +2523,33 @@ public class Scribe implements IJavaDocTagConstants { currentTokenStartPosition = this.scanner.currentPosition; hasLineComment = true; lines = 0; - if (this.useTags && !this.editsEnabled && foundTaskCount > previousFoundTaskCount) { - setEditsEnabled(foundTaskCount, previousFoundTaskCount); + if (this.useTags && !this.editsEnabled) { + if (foundTaskCount > 0) { + setEditsEnabled(foundTaskCount); + } else if (this.tagsKind == this.currentToken) { + this.editsEnabled = CharOperation.fragmentEquals(this.enablingTag, this.scanner.source, tokenStartPosition, true); + } } break; case TerminalTokens.TokenNameCOMMENT_BLOCK : - if (this.useTags && this.editsEnabled && foundTaskCount > previousFoundTaskCount) { - setEditsEnabled(foundTaskCount, previousFoundTaskCount); - if (!this.editsEnabled && this.editsIndex > 1) { - OptimizedReplaceEdit currentEdit = this.edits[this.editsIndex-1]; - if (this.scanner.startPosition == currentEdit.offset+currentEdit.length) { - printNewLinesBeforeDisablingComment(); + if (this.useTags && this.editsEnabled) { + boolean turnOff = false; + if (foundTaskCount > 0) { + setEditsEnabled(foundTaskCount); + turnOff = true; + } else if (this.tagsKind == this.currentToken + && CharOperation.fragmentEquals(this.disablingTag, this.scanner.source, tokenStartPosition, true)) { + this.editsEnabled = false; + turnOff = true; + } + if (turnOff) { + if (!this.editsEnabled && this.editsIndex > 1) { + OptimizedReplaceEdit currentEdit = this.edits[this.editsIndex-1]; + if (this.scanner.startPosition == currentEdit.offset+currentEdit.length) { + printNewLinesBeforeDisablingComment(); + } } } - previousFoundTaskCount = foundTaskCount; } if (trailing > NO_TRAILING_COMMENT && lines >= 1) { // a block comment on next line means that there's no trailing comment @@ -2559,20 +2573,23 @@ public class Scribe implements IJavaDocTagConstants { hasLineComment = false; hasComment = true; lines = 0; - if (this.useTags && !this.editsEnabled && foundTaskCount > previousFoundTaskCount) { - setEditsEnabled(foundTaskCount, previousFoundTaskCount); + if (this.useTags && !this.editsEnabled) { + if (foundTaskCount > 0) { + setEditsEnabled(foundTaskCount); + } else if (this.tagsKind == this.currentToken) { + this.editsEnabled = CharOperation.fragmentEquals(this.enablingTag, this.scanner.source, tokenStartPosition, true); + } } break; case TerminalTokens.TokenNameCOMMENT_JAVADOC : - if (this.useTags && this.editsEnabled && foundTaskCount > previousFoundTaskCount) { - setEditsEnabled(foundTaskCount, previousFoundTaskCount); + if (this.useTags && this.editsEnabled && foundTaskCount > 0) { + setEditsEnabled(foundTaskCount); if (!this.editsEnabled && this.editsIndex > 1) { OptimizedReplaceEdit currentEdit = this.edits[this.editsIndex-1]; if (this.scanner.startPosition == currentEdit.offset+currentEdit.length) { printNewLinesBeforeDisablingComment(); } } - previousFoundTaskCount = foundTaskCount; } if (trailing > NO_TRAILING_COMMENT) { // a javadoc comment should not be considered as a trailing comment @@ -2596,8 +2613,8 @@ public class Scribe implements IJavaDocTagConstants { } else { printBlockComment(true); } - if (this.useTags && !this.editsEnabled && foundTaskCount > previousFoundTaskCount) { - setEditsEnabled(foundTaskCount, previousFoundTaskCount); + if (this.useTags && !this.editsEnabled && foundTaskCount > 0) { + setEditsEnabled(foundTaskCount); } printNewLine(); currentTokenStartPosition = this.scanner.currentPosition; @@ -2611,7 +2628,6 @@ public class Scribe implements IJavaDocTagConstants { this.scanner.resetTo(currentTokenStartPosition, this.scannerEndPosition - 1); return; } - previousFoundTaskCount = foundTaskCount; } } catch (InvalidInputException e) { throw new AbortFormatting(e); @@ -2686,8 +2702,7 @@ public class Scribe implements IJavaDocTagConstants { if (this.tabLength == 0) { similarCommentsIndentation = relativeIndentation == 0; } else if (relativeIndentation > -this.tabLength) { - similarCommentsIndentation = this.formatter.preferences.comment_format_line_comment_starting_on_first_column || - (currentCommentIndentation != 0 && this.lastLineComment.currentIndentation != 0); + similarCommentsIndentation = relativeIndentation == 0 || currentCommentIndentation != 0 && this.lastLineComment.currentIndentation != 0; } if (similarCommentsIndentation && this.lastLineComment.indentation != this.indentationLevel) { int currentIndentationLevel = this.indentationLevel; @@ -3925,7 +3940,9 @@ public class Scribe implements IJavaDocTagConstants { // Replace the new line with a single space when there's only one separator // or, if necessary, print the indentation on the last line if (!multiLinesBlock) { - addReplaceEdit(firstLineEnd, end, " "); //$NON-NLS-1$ + if (firstLineEnd > 0) { + addReplaceEdit(firstLineEnd, end, " "); //$NON-NLS-1$ + } } else if (secondLineStart > 0) { if (newLineString == null) { @@ -4441,6 +4458,9 @@ public class Scribe implements IJavaDocTagConstants { boolean hasComment = false; boolean hasModifiers = false; while ((this.currentToken = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + int foundTaskCount = this.scanner.foundTaskCount; + int tokenStartPosition = this.scanner.getCurrentTokenStartPosition(); + int tokenEndPosition = this.scanner.getCurrentTokenEndPosition(); switch(this.currentToken) { case TerminalTokens.TokenNamepublic : case TerminalTokens.TokenNameprotected : @@ -4480,8 +4500,23 @@ public class Scribe implements IJavaDocTagConstants { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=122247 boolean shouldAddNewLine = false; switch (annotationSourceKind) { - case ICodeFormatterConstants.ANNOTATION_ON_MEMBER : - if (this.formatter.preferences.insert_new_line_after_annotation_on_member) { + case ICodeFormatterConstants.ANNOTATION_ON_TYPE : + if (this.formatter.preferences.insert_new_line_after_annotation_on_type) { + shouldAddNewLine = true; + } + break; + case ICodeFormatterConstants.ANNOTATION_ON_FIELD : + if (this.formatter.preferences.insert_new_line_after_annotation_on_field) { + shouldAddNewLine = true; + } + break; + case ICodeFormatterConstants.ANNOTATION_ON_METHOD : + if (this.formatter.preferences.insert_new_line_after_annotation_on_method) { + shouldAddNewLine = true; + } + break; + case ICodeFormatterConstants.ANNOTATION_ON_PACKAGE : + if (this.formatter.preferences.insert_new_line_after_annotation_on_package) { shouldAddNewLine = true; } break; @@ -4508,17 +4543,66 @@ public class Scribe implements IJavaDocTagConstants { currentTokenStartPosition = this.scanner.currentPosition; break; case TerminalTokens.TokenNameCOMMENT_BLOCK : - printBlockComment(false); - currentTokenStartPosition = this.scanner.currentPosition; - hasComment = true; - break; case TerminalTokens.TokenNameCOMMENT_JAVADOC : - printBlockComment(true); + if (this.useTags && this.editsEnabled) { + boolean turnOff = false; + if (foundTaskCount > 0) { + setEditsEnabled(foundTaskCount); + turnOff = true; + } else if (this.tagsKind == this.currentToken + && CharOperation.equals(this.disablingTag, this.scanner.source, tokenStartPosition, tokenEndPosition+1)) { + this.editsEnabled = false; + turnOff = true; + } + if (turnOff) { + if (!this.editsEnabled && this.editsIndex > 1) { + OptimizedReplaceEdit currentEdit = this.edits[this.editsIndex-1]; + if (this.scanner.startPosition == currentEdit.offset+currentEdit.length) { + printNewLinesBeforeDisablingComment(); + } + } + } + } + printBlockComment(this.currentToken == TerminalTokens.TokenNameCOMMENT_JAVADOC); + if (this.useTags && !this.editsEnabled) { + if (foundTaskCount > 0) { + setEditsEnabled(foundTaskCount); + } else if (this.tagsKind == this.currentToken) { + this.editsEnabled = CharOperation.equals(this.enablingTag, this.scanner.source, tokenStartPosition, tokenEndPosition+1); + } + } currentTokenStartPosition = this.scanner.currentPosition; hasComment = true; break; case TerminalTokens.TokenNameCOMMENT_LINE : + tokenEndPosition = -this.scanner.commentStops[this.scanner.commentPtr]; + if (this.useTags && this.editsEnabled) { + boolean turnOff = false; + if (foundTaskCount > 0) { + setEditsEnabled(foundTaskCount); + turnOff = true; + } else if (this.tagsKind == this.currentToken + && CharOperation.equals(this.disablingTag, this.scanner.source, tokenStartPosition, tokenEndPosition)) { + this.editsEnabled = false; + turnOff = true; + } + if (turnOff) { + if (!this.editsEnabled && this.editsIndex > 1) { + OptimizedReplaceEdit currentEdit = this.edits[this.editsIndex-1]; + if (this.scanner.startPosition == currentEdit.offset+currentEdit.length) { + printNewLinesBeforeDisablingComment(); + } + } + } + } printLineComment(); + if (this.useTags && !this.editsEnabled) { + if (foundTaskCount > 0) { + setEditsEnabled(foundTaskCount); + } else if (this.tagsKind == this.currentToken) { + this.editsEnabled = CharOperation.equals(this.enablingTag, this.scanner.source, tokenStartPosition, tokenEndPosition); + } + } currentTokenStartPosition = this.scanner.currentPosition; break; case TerminalTokens.TokenNameWHITESPACE : @@ -4974,8 +5058,8 @@ public class Scribe implements IJavaDocTagConstants { * disabling/enabling tags in a comment, hence the last one will be the one really * changing the formatter behavior... */ - private void setEditsEnabled(int count, int previous) { - for (int i=previous; i<count; i++) { + private void setEditsEnabled(int count) { + for (int i=0; i<count; i++) { if (this.disablingTag != null && CharOperation.equals(this.scanner.foundTaskTags[i], this.disablingTag)) { this.editsEnabled = false; } |