<s> package org . eclipse . jdt . internal . formatter ; import java . io . IOException ; import java . io . StringReader ; import java . util . Arrays ; import java . util . Comparator ; import java . util . Map ; import org . eclipse . jdt . core . JavaCore ; import org . eclipse . jdt . core . compiler . CharOperation ; import org . eclipse . jdt . core . compiler . InvalidInputException ; import org . eclipse . jdt . core . formatter . CodeFormatter ; import org . eclipse . jdt . internal . compiler . ASTVisitor ; import org . eclipse . jdt . internal . compiler . ast . Annotation ; import org . eclipse . jdt . internal . compiler . classfmt . ClassFileConstants ; import org . eclipse . jdt . internal . compiler . impl . CompilerOptions ; import org . eclipse . jdt . internal . compiler . lookup . BlockScope ; import org . eclipse . jdt . internal . compiler . parser . Parser ; import org . eclipse . jdt . internal . compiler . parser . Scanner ; import org . eclipse . jdt . internal . compiler . parser . ScannerHelper ; import org . eclipse . jdt . internal . compiler . parser . TerminalTokens ; import org . eclipse . jdt . internal . compiler . util . Util ; import org . eclipse . jdt . internal . core . util . CodeSnippetParsingUtil ; import org . eclipse . jdt . internal . core . util . RecordedParsingInformation ; import org . eclipse . jdt . internal . formatter . align . Alignment ; import org . eclipse . jdt . internal . formatter . align . AlignmentException ; import org . eclipse . jdt . internal . formatter . comment . CommentFormatterUtil ; import org . eclipse . jdt . internal . formatter . comment . HTMLEntity2JavaReader ; import org . eclipse . jdt . internal . formatter . comment . IJavaDocTagConstants ; import org . eclipse . jdt . internal . formatter . comment . Java2HTMLEntityReader ; import org . eclipse . jface . text . BadLocationException ; import org . eclipse . jface . text . DefaultLineTracker ; import org . eclipse . jface . text . ILineTracker ; import org . eclipse . jface . text . IRegion ; import org . eclipse . jface . text . Region ; import org . eclipse . text . edits . MalformedTreeException ; import org . eclipse . text . edits . MultiTextEdit ; import org . eclipse . text . edits . ReplaceEdit ; import org . eclipse . text . edits . TextEdit ; public class Scribe implements IJavaDocTagConstants { private static final int INITIAL_SIZE = 100 ; private boolean checkLineWrapping ; public int column ; private int [ ] [ ] commentPositions ; public Alignment currentAlignment ; public int currentToken ; private OptimizedReplaceEdit [ ] edits ; public int editsIndex ; public CodeFormatterVisitor formatter ; public int indentationLevel ; public int lastNumberOfNewLines ; private boolean preserveLineBreakIndentation = false ; public int line ; private int [ ] lineEnds ; private int maxLines ; public Alignment memberAlignment ; public boolean needSpace = false ; final private String lineSeparator ; final private String lineSeparatorAndSpace ; final private char firstLS ; final private int lsLength ; public int nlsTagCounter ; public int pageWidth ; public boolean pendingSpace = false ; public Scanner scanner ; public int scannerEndPosition ; public int tabLength ; public int indentationSize ; private final IRegion [ ] regions ; private IRegion [ ] adaptedRegions ; public int tabChar ; public int numberOfIndentations ; private boolean useTabsOnlyForLeadingIndents ; private final boolean indentEmptyLines ; int blank_lines_between_import_groups = - 1 ; public static final int DO_NOT_PRESERVE_EMPTY_LINES = - 1 ; public static final int PRESERVE_EMPTY_LINES_KEEP_LAST_NEW_LINES_INDENTATION = 1 ; public static final int PRESERVE_EMPTY_LINES_IN_FORMAT_LEFT_CURLY_BRACE = 2 ; public static final int PRESERVE_EMPTY_LINES_IN_STRING_LITERAL_CONCATENATION = 3 ; public static final int PRESERVE_EMPTY_LINES_IN_CLOSING_ARRAY_INITIALIZER = 4 ; public static final int PRESERVE_EMPTY_LINES_IN_FORMAT_OPENING_BRACE = 5 ; public static final int PRESERVE_EMPTY_LINES_IN_BINARY_EXPRESSION = 6 ; public static final int PRESERVE_EMPTY_LINES_IN_EQUALITY_EXPRESSION = 7 ; public static final int PRESERVE_EMPTY_LINES_BEFORE_ELSE = 8 ; public static final int PRESERVE_EMPTY_LINES_IN_SWITCH_CASE = 9 ; public static final int PRESERVE_EMPTY_LINES_AT_END_OF_METHOD_DECLARATION = 10 ; public static final int PRESERVE_EMPTY_LINES_AT_END_OF_BLOCK = 11 ; final static int PRESERVE_EMPTY_LINES_DO_NOT_USE_ANY_INDENTATION = - 1 ; final static int PRESERVE_EMPTY_LINES_USE_CURRENT_INDENTATION = 0 ; final static int PRESERVE_EMPTY_LINES_USE_TEMPORARY_INDENTATION = 1 ; boolean editsEnabled ; boolean useTags ; int tagsKind ; private static final int INCLUDE_BLOCK_COMMENTS = CodeFormatter . F_INCLUDE_COMMENTS | CodeFormatter . K_MULTI_LINE_COMMENT ; private static final int INCLUDE_JAVA_DOC = CodeFormatter . F_INCLUDE_COMMENTS | CodeFormatter . K_JAVA_DOC ; private static final int INCLUDE_LINE_COMMENTS = CodeFormatter . F_INCLUDE_COMMENTS | CodeFormatter . K_SINGLE_LINE_COMMENT ; private static final int SKIP_FIRST_WHITESPACE_TOKEN = - 2 ; private static final int INVALID_TOKEN = 2000 ; static final int NO_TRAILING_COMMENT = 0x0000 ; static final int BASIC_TRAILING_COMMENT = 0x0100 ; static final int COMPLEX_TRAILING_COMMENT = 0x0200 ; static final int IMPORT_TRAILING_COMMENT = COMPLEX_TRAILING_COMMENT | 0x0001 ; static final int UNMODIFIABLE_TRAILING_COMMENT = 0x0400 ; private int formatComments = 0 ; private int headerEndPosition = - 1 ; String commentIndentation ; static class LineComment { boolean contiguous = false ; int currentIndentation , indentation ; int lines ; char [ ] leadingSpaces ; } final LineComment lastLineComment = new LineComment ( ) ; private FormatterCommentParser formatterCommentParser ; OptimizedReplaceEdit previousDisabledEdit ; private char [ ] disablingTag , enablingTag ; private String [ ] newEmptyLines = new String [ 10 ] ; private static String [ ] COMMENT_INDENTATIONS = new String [ 20 ] ; private final StringBuffer tempBuffer = new StringBuffer ( ) ; private final StringBuffer blockCommentBuffer = new StringBuffer ( ) ; private final StringBuffer blockCommentTokensBuffer = new StringBuffer ( ) ; private final StringBuffer codeSnippetBuffer = new StringBuffer ( ) ; private final StringBuffer javadocBlockRefBuffer = new StringBuffer ( ) ; private final StringBuffer javadocGapLinesBuffer = new StringBuffer ( ) ; private StringBuffer [ ] javadocHtmlTagBuffers = new StringBuffer [ 5 ] ; private final StringBuffer javadocTextBuffer = new StringBuffer ( ) ; private final StringBuffer javadocTokensBuffer = new StringBuffer ( ) ; Scribe ( CodeFormatterVisitor formatter , long sourceLevel , IRegion [ ] regions , CodeSnippetParsingUtil codeSnippetParsingUtil , boolean includeComments ) { initializeScanner ( sourceLevel , formatter . preferences ) ; this . formatter = formatter ; this . pageWidth = formatter . preferences . page_width ; this . tabLength = formatter . preferences . tab_size ; this . indentationLevel = 0 ; this . numberOfIndentations = 0 ; this . useTabsOnlyForLeadingIndents = formatter . preferences . use_tabs_only_for_leading_indentations ; this . indentEmptyLines = formatter . preferences . indent_empty_lines ; this . tabChar = formatter . preferences . tab_char ; if ( this . tabChar == DefaultCodeFormatterOptions . MIXED ) { this . indentationSize = formatter . preferences . indentation_size ; } else { this . indentationSize = this . tabLength ; } this . lineSeparator = formatter . preferences . line_separator ; this . lineSeparatorAndSpace = this . lineSeparator + ' ' ; this . firstLS = this . lineSeparator . charAt ( 0 ) ; this . lsLength = this . lineSeparator . length ( ) ; this . indentationLevel = formatter . preferences . initial_indentation_level * this . indentationSize ; this . regions = regions ; if ( codeSnippetParsingUtil != null ) { final RecordedParsingInformation information = codeSnippetParsingUtil . recordedParsingInformation ; if ( information != null ) { this . lineEnds = information . lineEnds ; this . commentPositions = information . commentPositions ; } } if ( formatter . preferences . comment_format_line_comment ) this . formatComments |= CodeFormatter . K_SINGLE_LINE_COMMENT ; if ( formatter . preferences . comment_format_block_comment ) this . formatComments |= CodeFormatter . K_MULTI_LINE_COMMENT ; if ( formatter . preferences . comment_format_javadoc_comment ) this . formatComments |= CodeFormatter . K_JAVA_DOC ; if ( includeComments ) this . formatComments |= CodeFormatter . F_INCLUDE_COMMENTS ; reset ( ) ; } private void adaptRegions ( ) { int max = this . regions . length ; if ( max == 1 ) { if ( this . regions [ 0 ] . getOffset ( ) == 0 && this . regions [ 0 ] . getLength ( ) == this . scannerEndPosition ) { this . adaptedRegions = this . regions ; return ; } } this . adaptedRegions = new IRegion [ max ] ; int commentIndex = 0 ; for ( int i = 0 ; i < max ; i ++ ) { IRegion aRegion = this . regions [ i ] ; int offset = aRegion . getOffset ( ) ; int length = aRegion . getLength ( ) ; int index = getCommentIndex ( commentIndex , offset ) ; int adaptedOffset = offset ; int adaptedLength = length ; if ( index >= 0 ) { adaptedOffset = this . commentPositions [ index ] [ 0 ] ; if ( adaptedOffset >= 0 ) { adaptedLength = length + offset - adaptedOffset ; commentIndex = index ; } } index = getCommentIndex ( commentIndex , offset + length - 1 ) ; if ( index >= 0 && this . commentPositions [ index ] [ 0 ] >= 0 ) { int commentEnd = this . commentPositions [ index ] [ 1 ] ; if ( commentEnd < 0 ) commentEnd = - commentEnd ; adaptedLength = commentEnd - adaptedOffset ; commentIndex = index ; } if ( adaptedLength != length ) { this . adaptedRegions [ i ] = new Region ( adaptedOffset , adaptedLength ) ; } else { this . adaptedRegions [ i ] = aRegion ; } } } private void adaptEdits ( ) { int max = this . regions . length ; if ( max == 1 ) { if ( this . regions [ 0 ] . getOffset ( ) == 0 && this . regions [ 0 ] . getLength ( ) == this . scannerEndPosition ) { return ; } } OptimizedReplaceEdit [ ] sortedEdits = new OptimizedReplaceEdit [ this . editsIndex ] ; System . arraycopy ( this . edits , 0 , sortedEdits , 0 , this . editsIndex ) ; Arrays . sort ( sortedEdits , new Comparator ( ) { public int compare ( Object o1 , Object o2 ) { OptimizedReplaceEdit edit1 = ( OptimizedReplaceEdit ) o1 ; OptimizedReplaceEdit edit2 = ( OptimizedReplaceEdit ) o2 ; return edit1 . offset - edit2 . offset ; } } ) ; int currentEdit = - 1 ; for ( int i = 0 ; i < max ; i ++ ) { IRegion region = this . adaptedRegions [ i ] ; int offset = region . getOffset ( ) ; int length = region . getLength ( ) ; int index = adaptEdit ( sortedEdits , currentEdit , offset , offset + length ) ; if ( index != - 1 ) { currentEdit = index ; } } if ( currentEdit != - 1 ) { int length = sortedEdits . length ; for ( int e = currentEdit ; e < length ; e ++ ) { sortedEdits [ e ] . offset = - 1 ; } } } private int adaptEdit ( OptimizedReplaceEdit [ ] sortedEdits , int start , int regionStart , int regionEnd ) { 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 ; while ( bottom <= top ) { i = bottom + ( top - bottom ) / 2 ; edit = sortedEdits [ i ] ; int editStart = edit . offset ; int editEnd = editStart + edit . length ; if ( editStart > regionStart ) { top = i - 1 ; if ( editStart > regionEnd ) { topEnd = top ; } } else { if ( editEnd < regionStart ) { bottom = i + 1 ; } else { int linesOutside = 0 ; StringBuffer spacesOutside = new StringBuffer ( ) ; this . scanner . resetTo ( editStart , editEnd - 1 ) ; 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 ; } } edit . offset = regionStart ; int editLength = edit . length ; edit . length -= edit . offset - editStart ; int length = edit . replacement . length ( ) ; if ( length > 0 ) { int linesReplaced = 0 ; for ( int idx = 0 ; idx < length ; idx ++ ) { if ( edit . replacement . charAt ( idx ) == '\n' ) linesReplaced ++ ; } if ( editLength > 0 && edit . length == 0 && editEnd == regionStart && linesReplaced == 0 && linesOutside == 0 ) { edit . offset = - 1 ; } else { 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 ++ ; } 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 ; } } if ( replacementStart > length || ( replacementStart == length && spacesOutsideLength > 0 ) ) { edit . offset = - 1 ; } else if ( spacesOutsideLength == 0 && replacementStart == length ) { edit . replacement = "" ; } else { edit . replacement = edit . replacement . substring ( replacementStart ) ; } } } } } overlapIndex = i ; break ; } } } int validIndex = ( overlapIndex != - 1 ) ? overlapIndex : bottom ; if ( overlapIndex != - 1 ) bottom = overlapIndex ; while ( bottom <= topEnd ) { i = bottom + ( topEnd - bottom ) / 2 ; edit = sortedEdits [ i ] ; int editStart = edit . offset ; int editEnd = editStart + edit . length ; if ( regionEnd < editStart ) { topEnd = i - 1 ; } else if ( regionEnd == editStart ) { topEnd = i - 1 ; if ( edit . length == 0 ) { int nrLength = 0 ; int rLength = edit . replacement . length ( ) ; if ( nrLength < rLength ) { 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 ) { bottom = i + 1 ; } else { 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 ++ ; } } int length = edit . replacement . length ( ) ; if ( length > 0 ) { int linesReplaced = 0 ; for ( int idx = 0 ; idx < length ; idx ++ ) { if ( edit . replacement . charAt ( idx ) == '\n' ) linesReplaced ++ ; } if ( linesReplaced == 0 ) { edit . replacement = "" ; } else { int linesCount = linesReplaced > linesOutside ? linesReplaced - linesOutside : 0 ; if ( linesCount == 0 ) { edit . replacement = "" ; } else { edit . replacement = getNewLineString ( linesCount ) ; } } } edit . length = regionEnd - editStart ; topEnd = i ; break ; } } for ( int e = initialStart ; e < validIndex ; e ++ ) { sortedEdits [ e ] . offset = - 1 ; } return topEnd + 1 ; } private final void addDeleteEdit ( int start , int end ) { if ( this . edits . length == this . editsIndex ) { resize ( ) ; } addOptimizedReplaceEdit ( start , end - start + 1 , Util . EMPTY_STRING ) ; } public final void addInsertEdit ( int insertPosition , String insertedString ) { if ( this . edits . length == this . editsIndex ) { resize ( ) ; } addOptimizedReplaceEdit ( insertPosition , 0 , insertedString ) ; } private final void addOptimizedReplaceEdit ( int offset , int length , String replacement ) { if ( ! this . editsEnabled ) { if ( this . previousDisabledEdit != null && this . previousDisabledEdit . offset == offset ) { replacement = this . previousDisabledEdit . replacement ; } this . previousDisabledEdit = null ; if ( replacement . indexOf ( this . lineSeparator ) >= 0 ) { if ( length == 0 || printNewLinesCharacters ( offset , length ) ) { this . previousDisabledEdit = new OptimizedReplaceEdit ( offset , length , replacement ) ; } } return ; } if ( this . editsIndex > 0 ) { final OptimizedReplaceEdit previous = this . edits [ this . editsIndex - 1 ] ; final int previousOffset = previous . offset ; final int previousLength = previous . length ; final int endOffsetOfPreviousEdit = previousOffset + previousLength ; final int replacementLength = replacement . length ( ) ; final String previousReplacement = previous . replacement ; final int previousReplacementLength = previousReplacement . length ( ) ; if ( previousOffset == offset && previousLength == length && ( replacementLength == 0 || previousReplacementLength == 0 ) ) { if ( this . currentAlignment != null ) { final Location location = this . currentAlignment . location ; if ( location . editsIndex == this . editsIndex ) { location . editsIndex -- ; location . textEdit = previous ; } } this . editsIndex -- ; return ; } if ( endOffsetOfPreviousEdit == offset ) { if ( length != 0 ) { if ( replacementLength != 0 ) { this . edits [ this . editsIndex - 1 ] = new OptimizedReplaceEdit ( previousOffset , previousLength + length , previousReplacement + replacement ) ; } else if ( previousLength + length == previousReplacementLength ) { boolean canBeRemoved = true ; loop : for ( int i = previousOffset ; i < previousOffset + previousReplacementLength ; i ++ ) { if ( this . scanner . source [ i ] != previousReplacement . charAt ( i - previousOffset ) ) { this . edits [ this . editsIndex - 1 ] = new OptimizedReplaceEdit ( previousOffset , previousReplacementLength , previousReplacement ) ; canBeRemoved = false ; break loop ; } } if ( canBeRemoved ) { if ( this . currentAlignment != null ) { final Location location = this . currentAlignment . location ; if ( location . editsIndex == this . editsIndex ) { location . editsIndex -- ; location . textEdit = previous ; } } this . editsIndex -- ; } } else { this . edits [ this . editsIndex - 1 ] = new OptimizedReplaceEdit ( previousOffset , previousLength + length , previousReplacement ) ; } } else { if ( replacementLength != 0 ) { this . edits [ this . editsIndex - 1 ] = new OptimizedReplaceEdit ( previousOffset , previousLength , previousReplacement + replacement ) ; } } } else if ( ( offset + length == previousOffset ) && ( previousLength + length == replacementLength + previousReplacementLength ) ) { boolean canBeRemoved = true ; String totalReplacement = replacement + previousReplacement ; loop : for ( int i = 0 ; i < previousLength + length ; i ++ ) { if ( this . scanner . source [ i + offset ] != totalReplacement . charAt ( i ) ) { this . edits [ this . editsIndex - 1 ] = new OptimizedReplaceEdit ( offset , previousLength + length , totalReplacement ) ; canBeRemoved = false ; break loop ; } } if ( canBeRemoved ) { if ( this . currentAlignment != null ) { final Location location = this . currentAlignment . location ; if ( location . editsIndex == this . editsIndex ) { location . editsIndex -- ; location . textEdit = previous ; } } this . editsIndex -- ; } } else { this . edits [ this . editsIndex ++ ] = new OptimizedReplaceEdit ( offset , length , replacement ) ; } } else { this . edits [ this . editsIndex ++ ] = new OptimizedReplaceEdit ( offset , length , replacement ) ; } } public final void addReplaceEdit ( int start , int end , String replacement ) { if ( this . edits . length == this . editsIndex ) { resize ( ) ; } addOptimizedReplaceEdit ( start , end - start + 1 , replacement ) ; } public void alignFragment ( Alignment alignment , int fragmentIndex ) { alignment . fragmentIndex = fragmentIndex ; alignment . checkColumn ( ) ; alignment . performFragmentEffect ( ) ; } public void checkNLSTag ( int sourceStart ) { if ( hasNLSTag ( sourceStart ) ) { this . nlsTagCounter ++ ; } } private int consumeInvalidToken ( int end ) { this . scanner . resetTo ( this . scanner . startPosition , end ) ; if ( this . scanner . currentCharacter == '\\' ) { this . scanner . currentPosition = this . scanner . startPosition + 1 ; } int previousPosition = this . scanner . currentPosition ; char ch = ( char ) this . scanner . getNextChar ( ) ; if ( this . scanner . atEnd ( ) ) { return INVALID_TOKEN ; } while ( ! this . scanner . atEnd ( ) && ch != '*' && ! ScannerHelper . isWhitespace ( ch ) ) { previousPosition = this . scanner . currentPosition ; ch = ( char ) this . scanner . getNextChar ( ) ; } this . scanner . currentPosition = previousPosition ; return INVALID_TOKEN ; } public Alignment createAlignment ( int kind , int mode , int count , int sourceRestart ) { return createAlignment ( kind , mode , Alignment . R_INNERMOST , count , sourceRestart ) ; } public Alignment createAlignment ( int kind , int mode , int tieBreakRule , int count , int sourceRestart ) { return createAlignment ( kind , mode , tieBreakRule , count , sourceRestart , this . formatter . preferences . continuation_indentation , false ) ; } public Alignment createAlignment ( int kind , int mode , int count , int sourceRestart , int continuationIndent , boolean adjust ) { return createAlignment ( kind , mode , Alignment . R_INNERMOST , count , sourceRestart , continuationIndent , adjust ) ; } public Alignment createAlignment ( int kind , int mode , int tieBreakRule , int count , int sourceRestart , int continuationIndent , boolean adjust ) { Alignment alignment = new Alignment ( kind , mode , tieBreakRule , this , count , sourceRestart , continuationIndent ) ; if ( ( this . currentAlignment == null && this . formatter . expressionsDepth >= 0 ) || ( this . currentAlignment != null && this . currentAlignment . kind == Alignment . BINARY_EXPRESSION && ( this . formatter . expressionsPos & CodeFormatterVisitor . EXPRESSIONS_POS_MASK ) == CodeFormatterVisitor . EXPRESSIONS_POS_BETWEEN_TWO ) ) { switch ( kind ) { case Alignment . CONDITIONAL_EXPRESSION : case Alignment . MESSAGE_ARGUMENTS : case Alignment . MESSAGE_SEND : if ( this . formatter . lastBinaryExpressionAlignmentBreakIndentation == alignment . breakIndentationLevel ) { alignment . breakIndentationLevel += this . indentationSize ; alignment . shiftBreakIndentationLevel += this . indentationSize ; this . formatter . lastBinaryExpressionAlignmentBreakIndentation = 0 ; } break ; } } if ( adjust && this . memberAlignment != null ) { Alignment current = this . memberAlignment ; while ( current . enclosing != null ) { current = current . enclosing ; } if ( ( current . mode & Alignment . M_MULTICOLUMN ) != 0 ) { final int indentSize = this . indentationSize ; switch ( current . chunkKind ) { case Alignment . CHUNK_METHOD : case Alignment . CHUNK_TYPE : if ( ( mode & Alignment . M_INDENT_BY_ONE ) != 0 ) { alignment . breakIndentationLevel = this . indentationLevel + indentSize ; } else { alignment . breakIndentationLevel = this . indentationLevel + continuationIndent * indentSize ; } alignment . update ( ) ; break ; case Alignment . CHUNK_FIELD : if ( ( mode & Alignment . M_INDENT_BY_ONE ) != 0 ) { alignment . breakIndentationLevel = current . originalIndentationLevel + indentSize ; } else { alignment . breakIndentationLevel = current . originalIndentationLevel + continuationIndent * indentSize ; } alignment . update ( ) ; break ; } } else { switch ( current . mode & Alignment . SPLIT_MASK ) { case Alignment . M_COMPACT_SPLIT : case Alignment . M_COMPACT_FIRST_BREAK_SPLIT : case Alignment . M_NEXT_PER_LINE_SPLIT : case Alignment . M_NEXT_SHIFTED_SPLIT : case Alignment . M_ONE_PER_LINE_SPLIT : final int indentSize = this . indentationSize ; switch ( current . chunkKind ) { case Alignment . CHUNK_METHOD : case Alignment . CHUNK_TYPE : if ( ( mode & Alignment . M_INDENT_BY_ONE ) != 0 ) { alignment . breakIndentationLevel = this . indentationLevel + indentSize ; } else { alignment . breakIndentationLevel = this . indentationLevel + continuationIndent * indentSize ; } alignment . update ( ) ; break ; case Alignment . CHUNK_FIELD : if ( ( mode & Alignment . M_INDENT_BY_ONE ) != 0 ) { alignment . breakIndentationLevel = current . originalIndentationLevel + indentSize ; } else { alignment . breakIndentationLevel = current . originalIndentationLevel + continuationIndent * indentSize ; } alignment . update ( ) ; break ; } break ; } } } return alignment ; } public Alignment createMemberAlignment ( int kind , int mode , int count , int sourceRestart ) { Alignment mAlignment = createAlignment ( kind , mode , Alignment . R_INNERMOST , count , sourceRestart ) ; mAlignment . breakIndentationLevel = this . indentationLevel ; return mAlignment ; } public void enterAlignment ( Alignment alignment ) { alignment . enclosing = this . currentAlignment ; alignment . location . lastLocalDeclarationSourceStart = this . formatter . lastLocalDeclarationSourceStart ; this . currentAlignment = alignment ; } public void enterMemberAlignment ( Alignment alignment ) { alignment . enclosing = this . memberAlignment ; alignment . location . lastLocalDeclarationSourceStart = this . formatter . lastLocalDeclarationSourceStart ; this . memberAlignment = alignment ; } public void exitAlignment ( Alignment alignment , boolean discardAlignment ) { Alignment current = this . currentAlignment ; while ( current != null ) { if ( current == alignment ) break ; current = current . enclosing ; } if ( current == null ) { throw new AbortFormatting ( "" + alignment ) ; } this . indentationLevel = alignment . location . outputIndentationLevel ; this . numberOfIndentations = alignment . location . numberOfIndentations ; this . formatter . lastLocalDeclarationSourceStart = alignment . location . lastLocalDeclarationSourceStart ; if ( discardAlignment ) { this . currentAlignment = alignment . enclosing ; if ( this . currentAlignment == null ) { this . formatter . lastBinaryExpressionAlignmentBreakIndentation = 0 ; } } } public void exitMemberAlignment ( Alignment alignment ) { Alignment current = this . memberAlignment ; while ( current != null ) { if ( current == alignment ) break ; current = current . enclosing ; } if ( current == null ) { throw new AbortFormatting ( "" + alignment ) ; } this . indentationLevel = current . location . outputIndentationLevel ; this . numberOfIndentations = current . location . numberOfIndentations ; this . formatter . lastLocalDeclarationSourceStart = alignment . location . lastLocalDeclarationSourceStart ; this . memberAlignment = current . enclosing ; } public int getColumnIndentationLevel ( ) { return this . column - 1 ; } public final int getCommentIndex ( int position ) { if ( this . commentPositions == null ) return - 1 ; int length = this . commentPositions . length ; if ( length == 0 ) { return - 1 ; } int g = 0 , d = length - 1 ; int m = 0 ; while ( g <= d ) { m = g + ( d - g ) / 2 ; int bound = this . commentPositions [ m ] [ 1 ] ; if ( bound < 0 ) { bound = - bound ; } if ( bound < position ) { g = m + 1 ; } else if ( bound > position ) { d = m - 1 ; } else { return m ; } } return - ( g + 1 ) ; } private int getCommentIndex ( int start , int position ) { int commentsLength = this . commentPositions == null ? 0 : this . commentPositions . length ; if ( commentsLength == 0 ) return - 1 ; if ( position == 0 ) { if ( commentsLength > 0 && this . commentPositions [ 0 ] [ 0 ] == 0 ) { return 0 ; } return - 1 ; } int bottom = start , top = commentsLength - 1 ; int i = 0 ; int [ ] comment = null ; while ( bottom <= top ) { i = bottom + ( top - bottom ) / 2 ; comment = this . commentPositions [ i ] ; int commentStart = comment [ 0 ] ; if ( commentStart < 0 ) commentStart = - commentStart ; if ( position < commentStart ) { top = i - 1 ; } else { int commentEnd = comment [ 1 ] ; if ( commentEnd < 0 ) commentEnd = - commentEnd ; if ( position >= commentEnd ) { bottom = i + 1 ; } else { return i ; } } } return - 1 ; } private int getCurrentCommentIndentation ( int start ) { int linePtr = - Arrays . binarySearch ( this . lineEnds , start ) ; int indentation = 0 ; int beginningOfLine = getLineEnd ( linePtr - 1 ) + 1 ; if ( beginningOfLine == - 1 ) { beginningOfLine = 0 ; } int currentStartPosition = start ; char [ ] source = this . scanner . source ; while ( beginningOfLine > currentStartPosition ) { if ( linePtr > 0 ) { beginningOfLine = getLineEnd ( -- linePtr ) + 1 ; } else { beginningOfLine = 0 ; break ; } } for ( int i = beginningOfLine ; i < currentStartPosition ; i ++ ) { char currentCharacter = source [ i ] ; switch ( currentCharacter ) { case '\t' : if ( this . tabLength != 0 ) { int reminder = indentation % this . tabLength ; if ( reminder == 0 ) { indentation += this . tabLength ; } else { indentation = ( ( indentation / this . tabLength ) + 1 ) * this . tabLength ; } } break ; case '\r' : case '\n' : indentation = 0 ; break ; default : indentation ++ ; break ; } } return indentation ; } int getCurrentIndentation ( char [ ] whitespaces , int offset ) { if ( whitespaces == null ) return offset ; int length = whitespaces . length ; if ( this . tabLength == 0 ) return length ; int indentation = offset ; for ( int i = 0 ; i < length ; i ++ ) { char ch = whitespaces [ i ] ; switch ( ch ) { case '\t' : int reminder = indentation % this . tabLength ; if ( reminder == 0 ) { indentation += this . tabLength ; } else { indentation = ( ( indentation / this . tabLength ) + 1 ) * this . tabLength ; } break ; case '\r' : case '\n' : indentation = 0 ; break ; default : indentation ++ ; break ; } } return indentation ; } int getCurrentIndentation ( int start ) { int linePtr = Arrays . binarySearch ( this . lineEnds , start ) ; if ( linePtr < 0 ) { linePtr = - linePtr - 1 ; } int indentation = 0 ; int beginningOfLine = getLineEnd ( linePtr ) + 1 ; if ( beginningOfLine == - 1 ) { beginningOfLine = 0 ; } char [ ] source = this . scanner . source ; for ( int i = beginningOfLine ; i < start ; i ++ ) { char currentCharacter = source [ i ] ; switch ( currentCharacter ) { case '\t' : if ( this . tabLength != 0 ) { int reminder = indentation % this . tabLength ; if ( reminder == 0 ) { indentation += this . tabLength ; } else { indentation = ( ( indentation / this . tabLength ) + 1 ) * this . tabLength ; } } break ; case '\r' : case '\n' : indentation = 0 ; break ; case ' ' : indentation ++ ; break ; default : return indentation ; } } return indentation ; } public String getEmptyLines ( int linesNumber ) { if ( this . nlsTagCounter > 0 ) { return Util . EMPTY_STRING ; } String emptyLines ; if ( this . lastNumberOfNewLines == 0 ) { linesNumber ++ ; if ( this . indentEmptyLines ) { this . tempBuffer . setLength ( 0 ) ; for ( int i = 0 ; i < linesNumber ; i ++ ) { printIndentationIfNecessary ( this . tempBuffer ) ; this . tempBuffer . append ( this . lineSeparator ) ; this . column = 1 ; } emptyLines = this . tempBuffer . toString ( ) ; } else { emptyLines = getNewLineString ( linesNumber ) ; } this . lastNumberOfNewLines += linesNumber ; this . line += linesNumber ; this . column = 1 ; this . needSpace = false ; this . pendingSpace = false ; } else if ( this . lastNumberOfNewLines == 1 ) { if ( this . indentEmptyLines ) { this . tempBuffer . setLength ( 0 ) ; for ( int i = 0 ; i < linesNumber ; i ++ ) { printIndentationIfNecessary ( this . tempBuffer ) ; this . tempBuffer . append ( this . lineSeparator ) ; this . column = 1 ; } emptyLines = this . tempBuffer . toString ( ) ; } else { emptyLines = getNewLineString ( linesNumber ) ; } this . lastNumberOfNewLines += linesNumber ; this . line += linesNumber ; this . column = 1 ; this . needSpace = false ; this . pendingSpace = false ; } else { if ( ( this . lastNumberOfNewLines - 1 ) >= linesNumber ) { return Util . EMPTY_STRING ; } final int realNewLineNumber = linesNumber - this . lastNumberOfNewLines + 1 ; if ( this . indentEmptyLines ) { this . tempBuffer . setLength ( 0 ) ; for ( int i = 0 ; i < realNewLineNumber ; i ++ ) { printIndentationIfNecessary ( this . tempBuffer ) ; this . tempBuffer . append ( this . lineSeparator ) ; this . column = 1 ; } emptyLines = this . tempBuffer . toString ( ) ; } else { emptyLines = getNewLineString ( realNewLineNumber ) ; } this . lastNumberOfNewLines += realNewLineNumber ; this . line += realNewLineNumber ; this . column = 1 ; this . needSpace = false ; this . pendingSpace = false ; } return emptyLines ; } public OptimizedReplaceEdit getLastEdit ( ) { if ( this . editsIndex > 0 ) { return this . edits [ this . editsIndex - 1 ] ; } return null ; } public final int getLineEnd ( int lineNumber ) { if ( this . lineEnds == null ) return - 1 ; if ( lineNumber >= this . lineEnds . length + 1 ) return this . scannerEndPosition ; if ( lineNumber <= 0 ) return - 1 ; return this . lineEnds [ lineNumber - 1 ] ; } Alignment getMemberAlignment ( ) { return this . memberAlignment ; } public String getNewLine ( ) { if ( this . nlsTagCounter > 0 ) { return Util . EMPTY_STRING ; } if ( this . lastNumberOfNewLines >= 1 ) { this . column = 1 ; return Util . EMPTY_STRING ; } this . line ++ ; this . lastNumberOfNewLines = 1 ; this . column = 1 ; this . needSpace = false ; this . pendingSpace = false ; return this . lineSeparator ; } private String getNewLineString ( int linesCount ) { int length = this . newEmptyLines . length ; if ( linesCount > length ) { System . arraycopy ( this . newEmptyLines , 0 , this . newEmptyLines = new String [ linesCount + 10 ] , 0 , length ) ; } String newLineString = this . newEmptyLines [ linesCount - 1 ] ; if ( newLineString == null ) { this . tempBuffer . setLength ( 0 ) ; for ( int j = 0 ; j < linesCount ; j ++ ) { this . tempBuffer . append ( this . lineSeparator ) ; } newLineString = this . tempBuffer . toString ( ) ; this . newEmptyLines [ linesCount - 1 ] = newLineString ; } return newLineString ; } public int getNextIndentationLevel ( int someColumn ) { int indent = someColumn - 1 ; if ( indent == 0 ) return this . indentationLevel ; if ( this . tabChar == DefaultCodeFormatterOptions . TAB ) { if ( this . useTabsOnlyForLeadingIndents ) { return indent ; } if ( this . indentationSize == 0 ) { return indent ; } int rem = indent % this . indentationSize ; int addition = rem == 0 ? 0 : this . indentationSize - rem ; return indent + addition ; } return indent ; } private String getPreserveEmptyLines ( int count , int emptyLinesRules ) { if ( count == 0 ) { int currentIndentationLevel = this . indentationLevel ; int useAlignmentBreakIndentation = useAlignmentBreakIndentation ( emptyLinesRules ) ; switch ( useAlignmentBreakIndentation ) { case PRESERVE_EMPTY_LINES_DO_NOT_USE_ANY_INDENTATION : return Util . EMPTY_STRING ; default : StringBuffer buffer = new StringBuffer ( getNewLine ( ) ) ; printIndentationIfNecessary ( buffer ) ; if ( useAlignmentBreakIndentation == PRESERVE_EMPTY_LINES_USE_TEMPORARY_INDENTATION ) { this . indentationLevel = currentIndentationLevel ; } return buffer . toString ( ) ; } } if ( this . blank_lines_between_import_groups >= 0 ) { useAlignmentBreakIndentation ( emptyLinesRules ) ; return getEmptyLines ( this . blank_lines_between_import_groups ) ; } if ( this . formatter . preferences . number_of_empty_lines_to_preserve != 0 ) { useAlignmentBreakIndentation ( emptyLinesRules ) ; int linesToPreserve = Math . min ( count , this . formatter . preferences . number_of_empty_lines_to_preserve ) ; return getEmptyLines ( linesToPreserve ) ; } return getNewLine ( ) ; } private int useAlignmentBreakIndentation ( int emptyLinesRules ) { boolean specificEmptyLinesRule = emptyLinesRules != PRESERVE_EMPTY_LINES_KEEP_LAST_NEW_LINES_INDENTATION ; if ( ( this . currentAlignment != null || specificEmptyLinesRule ) && ! this . formatter . preferences . join_wrapped_lines ) { if ( this . lastNumberOfNewLines == 0 || specificEmptyLinesRule || this . formatter . arrayInitializersDepth >= 0 ) { boolean useAlignmentBreakIndentation ; boolean useAlignmentShiftBreakIndentation = false ; boolean useLastBinaryExpressionAlignmentBreakIndentation = false ; switch ( emptyLinesRules ) { case DO_NOT_PRESERVE_EMPTY_LINES : case PRESERVE_EMPTY_LINES_IN_SWITCH_CASE : case PRESERVE_EMPTY_LINES_AT_END_OF_METHOD_DECLARATION : case PRESERVE_EMPTY_LINES_AT_END_OF_BLOCK : return PRESERVE_EMPTY_LINES_DO_NOT_USE_ANY_INDENTATION ; case PRESERVE_EMPTY_LINES_IN_BINARY_EXPRESSION : useAlignmentBreakIndentation = true ; if ( ( this . formatter . expressionsPos & CodeFormatterVisitor . EXPRESSIONS_POS_MASK ) == CodeFormatterVisitor . EXPRESSIONS_POS_BETWEEN_TWO ) { useLastBinaryExpressionAlignmentBreakIndentation = true ; } break ; case PRESERVE_EMPTY_LINES_IN_EQUALITY_EXPRESSION : useAlignmentShiftBreakIndentation = this . currentAlignment == null || this . currentAlignment . kind == Alignment . BINARY_EXPRESSION ; useAlignmentBreakIndentation = ! useAlignmentShiftBreakIndentation ; break ; case PRESERVE_EMPTY_LINES_IN_FORMAT_OPENING_BRACE : useAlignmentBreakIndentation = this . formatter . arrayInitializersDepth <= 1 && this . currentAlignment != null && this . currentAlignment . kind == Alignment . ARRAY_INITIALIZER ; break ; case PRESERVE_EMPTY_LINES_IN_FORMAT_LEFT_CURLY_BRACE : useAlignmentBreakIndentation = false ; break ; default : if ( ( emptyLinesRules & 0xFFFF ) == PRESERVE_EMPTY_LINES_IN_CLOSING_ARRAY_INITIALIZER && this . scanner . currentCharacter == '}' ) { this . indentationLevel = emptyLinesRules >> 16 ; this . preserveLineBreakIndentation = true ; return PRESERVE_EMPTY_LINES_USE_CURRENT_INDENTATION ; } useAlignmentBreakIndentation = true ; break ; } Alignment alignment = this . currentAlignment ; if ( alignment == null ) { if ( useLastBinaryExpressionAlignmentBreakIndentation ) { if ( this . indentationLevel < this . formatter . lastBinaryExpressionAlignmentBreakIndentation ) { this . indentationLevel = this . formatter . lastBinaryExpressionAlignmentBreakIndentation ; } } if ( useAlignmentShiftBreakIndentation && this . memberAlignment != null ) { if ( this . indentationLevel < this . memberAlignment . shiftBreakIndentationLevel ) { this . indentationLevel = this . memberAlignment . shiftBreakIndentationLevel ; } } } else { if ( this . memberAlignment != null && this . memberAlignment . location . inputOffset > alignment . location . inputOffset ) { alignment = this . memberAlignment ; } if ( useLastBinaryExpressionAlignmentBreakIndentation ) { if ( this . indentationLevel < this . formatter . lastBinaryExpressionAlignmentBreakIndentation ) { this . indentationLevel = this . formatter . lastBinaryExpressionAlignmentBreakIndentation ; } } if ( useAlignmentBreakIndentation ) { if ( this . indentationLevel < alignment . breakIndentationLevel ) { this . indentationLevel = alignment . breakIndentationLevel ; } } else if ( useAlignmentShiftBreakIndentation ) { if ( this . indentationLevel < alignment . shiftBreakIndentationLevel ) { this . indentationLevel = alignment . shiftBreakIndentationLevel ; } } } this . preserveLineBreakIndentation = true ; if ( useLastBinaryExpressionAlignmentBreakIndentation || useAlignmentShiftBreakIndentation ) { return PRESERVE_EMPTY_LINES_USE_TEMPORARY_INDENTATION ; } return PRESERVE_EMPTY_LINES_USE_CURRENT_INDENTATION ; } } return PRESERVE_EMPTY_LINES_DO_NOT_USE_ANY_INDENTATION ; } public TextEdit getRootEdit ( ) { adaptRegions ( ) ; adaptEdits ( ) ; MultiTextEdit edit = null ; int regionsLength = this . adaptedRegions . length ; int textRegionStart ; int textRegionEnd ; if ( regionsLength == 1 ) { IRegion lastRegion = this . adaptedRegions [ 0 ] ; textRegionStart = lastRegion . getOffset ( ) ; textRegionEnd = textRegionStart + lastRegion . getLength ( ) ; } else { textRegionStart = this . adaptedRegions [ 0 ] . getOffset ( ) ; IRegion lastRegion = this . adaptedRegions [ regionsLength - 1 ] ; textRegionEnd = lastRegion . getOffset ( ) + lastRegion . getLength ( ) ; } int length = textRegionEnd - textRegionStart + 1 ; if ( textRegionStart <= 0 ) { if ( length <= 0 ) { edit = new MultiTextEdit ( 0 , 0 ) ; } else { edit = new MultiTextEdit ( 0 , textRegionEnd ) ; } } else { edit = new MultiTextEdit ( textRegionStart , length - 1 ) ; } for ( int i = 0 , max = this . editsIndex ; i < max ; i ++ ) { OptimizedReplaceEdit currentEdit = this . edits [ i ] ; 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 ) { CommentFormatterUtil . log ( ex ) ; throw ex ; } } } } this . edits = null ; return edit ; } public void handleLineTooLong ( ) { if ( this . formatter . preferences . wrap_outer_expressions_when_nested ) { handleLineTooLongSmartly ( ) ; return ; } int relativeDepth = 0 , outerMostDepth = - 1 ; Alignment targetAlignment = this . currentAlignment ; while ( targetAlignment != null ) { if ( targetAlignment . tieBreakRule == Alignment . R_OUTERMOST && targetAlignment . couldBreak ( ) ) { outerMostDepth = relativeDepth ; } targetAlignment = targetAlignment . enclosing ; relativeDepth ++ ; } if ( outerMostDepth >= 0 ) { throw new AlignmentException ( AlignmentException . LINE_TOO_LONG , outerMostDepth ) ; } relativeDepth = 0 ; targetAlignment = this . currentAlignment ; while ( targetAlignment != null ) { if ( targetAlignment . couldBreak ( ) ) { throw new AlignmentException ( AlignmentException . LINE_TOO_LONG , relativeDepth ) ; } targetAlignment = targetAlignment . enclosing ; relativeDepth ++ ; } } private void handleLineTooLongSmartly ( ) { int relativeDepth = 0 , outerMostDepth = - 1 ; Alignment targetAlignment = this . currentAlignment ; int previousKind = - 1 ; int insideMessage = 0 ; boolean insideStringConcat = false ; while ( targetAlignment != null ) { boolean couldBreak = targetAlignment . tieBreakRule == Alignment . R_OUTERMOST || ( ! insideStringConcat && insideMessage > 0 && targetAlignment . kind == Alignment . MESSAGE_ARGUMENTS && ( ! targetAlignment . wasReset ( ) || previousKind != Alignment . MESSAGE_SEND ) ) ; if ( couldBreak && targetAlignment . couldBreak ( ) ) { outerMostDepth = relativeDepth ; } switch ( targetAlignment . kind ) { case Alignment . MESSAGE_ARGUMENTS : case Alignment . MESSAGE_SEND : insideMessage ++ ; break ; case Alignment . STRING_CONCATENATION : insideStringConcat = true ; break ; } previousKind = targetAlignment . kind ; targetAlignment = targetAlignment . enclosing ; relativeDepth ++ ; } if ( outerMostDepth >= 0 ) { throw new AlignmentException ( AlignmentException . LINE_TOO_LONG , outerMostDepth ) ; } relativeDepth = 0 ; targetAlignment = this . currentAlignment ; AlignmentException alignmentException = null ; int msgArgsDepth = - 1 ; while ( targetAlignment != null ) { if ( targetAlignment . kind == Alignment . MESSAGE_ARGUMENTS ) { msgArgsDepth = relativeDepth ; } if ( alignmentException == null ) { if ( targetAlignment . couldBreak ( ) ) { alignmentException = new AlignmentException ( AlignmentException . LINE_TOO_LONG , relativeDepth ) ; if ( insideStringConcat ) throw alignmentException ; } } else if ( targetAlignment . wasSplit ) { if ( ! targetAlignment . wasReset ( ) ) { targetAlignment . reset ( ) ; if ( msgArgsDepth > alignmentException . relativeDepth ) { alignmentException . relativeDepth = msgArgsDepth ; } throw alignmentException ; } } targetAlignment = targetAlignment . enclosing ; relativeDepth ++ ; } if ( alignmentException != null ) { throw alignmentException ; } if ( this . currentAlignment != null ) { this . currentAlignment . blockAlign = false ; this . currentAlignment . tooLong = true ; } } private boolean hasNLSTag ( int sourceStart ) { if ( this . lineEnds == null ) return false ; int index = Arrays . binarySearch ( this . lineEnds , sourceStart ) ; int currentLineEnd = getLineEnd ( - index ) ; if ( currentLineEnd != - 1 ) { int commentIndex = getCommentIndex ( currentLineEnd ) ; if ( commentIndex < 0 ) { commentIndex = - commentIndex - 2 ; } if ( commentIndex >= 0 && commentIndex < this . commentPositions . length ) { int start = this . commentPositions [ commentIndex ] [ 0 ] ; if ( start < 0 ) { start = - start ; int lineIndexForComment = Arrays . binarySearch ( this . lineEnds , start ) ; if ( lineIndexForComment == index ) { return CharOperation . indexOf ( Scanner . TAG_PREFIX , this . scanner . source , true , start , currentLineEnd ) != - 1 ; } } } } return false ; } private boolean includesBlockComments ( ) { return ( ( this . formatComments & INCLUDE_BLOCK_COMMENTS ) == INCLUDE_BLOCK_COMMENTS && this . headerEndPosition < this . scanner . currentPosition ) || ( this . formatter . preferences . comment_format_header && this . headerEndPosition >= this . scanner . currentPosition ) ; } private boolean includesJavadocComments ( ) { return ( ( this . formatComments & INCLUDE_JAVA_DOC ) == INCLUDE_JAVA_DOC && this . headerEndPosition < this . scanner . currentPosition ) || ( this . formatter . preferences . comment_format_header && this . headerEndPosition >= this . scanner . currentPosition ) ; } private boolean includesLineComments ( ) { return ( ( this . formatComments & INCLUDE_LINE_COMMENTS ) == INCLUDE_LINE_COMMENTS && this . headerEndPosition < this . scanner . currentPosition ) || ( this . formatter . preferences . comment_format_header && this . headerEndPosition >= this . scanner . currentPosition ) ; } boolean includesComments ( ) { return ( this . formatComments & CodeFormatter . F_INCLUDE_COMMENTS ) != 0 ; } public void indent ( ) { this . indentationLevel += this . indentationSize ; this . numberOfIndentations ++ ; } void setIndentation ( int level , int n ) { this . indentationLevel = level + n * this . indentationSize ; this . numberOfIndentations = this . indentationLevel / this . indentationSize ; } 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 ; this . enablingTag = preferences . enabling_tag ; if ( this . disablingTag == null ) { if ( this . enablingTag != null ) { taskTags = new char [ ] [ ] { this . enablingTag } ; } } else if ( this . enablingTag == null ) { taskTags = new char [ ] [ ] { this . disablingTag } ; } else { 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 , sourceLevel , taskTags , null , true ) ; this . editsEnabled = true ; } private void initFormatterCommentParser ( ) { if ( this . formatterCommentParser == null ) { this . formatterCommentParser = new FormatterCommentParser ( this . scanner . sourceLevel ) ; } this . formatterCommentParser . scanner . setSource ( this . scanner . source ) ; this . formatterCommentParser . source = this . scanner . source ; this . formatterCommentParser . scanner . lineEnds = this . lineEnds ; this . formatterCommentParser . scanner . linePtr = this . maxLines ; this . formatterCommentParser . parseHtmlTags = this . formatter . preferences . comment_format_html ; } private boolean isOnFirstColumn ( int start ) { if ( this . lineEnds == null ) return start == 0 ; int index = Arrays . binarySearch ( this . lineEnds , start ) ; int previousLineEnd = getLineEnd ( - index - 1 ) ; return previousLineEnd != - 1 && previousLineEnd == start - 1 ; } private boolean isMeaningfulEdit ( OptimizedReplaceEdit edit ) { final int editLength = edit . length ; final int editReplacementLength = edit . replacement . length ( ) ; final int editOffset = edit . offset ; 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 ; } private void preserveEmptyLines ( int count , int insertPosition ) { if ( count > 0 ) { if ( this . blank_lines_between_import_groups >= 0 ) { printEmptyLines ( this . blank_lines_between_import_groups , insertPosition ) ; } else if ( this . formatter . preferences . number_of_empty_lines_to_preserve != 0 ) { int linesToPreserve = Math . min ( count , this . formatter . preferences . number_of_empty_lines_to_preserve ) ; printEmptyLines ( linesToPreserve , insertPosition ) ; } else { printNewLine ( insertPosition ) ; } } } private void print ( int length , boolean considerSpaceIfAny ) { if ( this . checkLineWrapping && length + this . column > this . pageWidth ) { handleLineTooLong ( ) ; } this . lastNumberOfNewLines = 0 ; if ( this . indentationLevel != 0 ) { printIndentationIfNecessary ( ) ; } if ( considerSpaceIfAny ) { space ( ) ; } if ( this . pendingSpace ) { addInsertEdit ( this . scanner . getCurrentTokenStartPosition ( ) , " " ) ; } this . pendingSpace = false ; this . column += length ; this . needSpace = true ; } private void printBlockComment ( boolean isJavadoc ) { int currentTokenStartPosition = this . scanner . getCurrentTokenStartPosition ( ) ; int currentTokenEndPosition = this . scanner . getCurrentTokenEndPosition ( ) + 1 ; boolean includesBlockComments = ! isJavadoc && includesBlockComments ( ) ; this . scanner . resetTo ( currentTokenStartPosition , currentTokenEndPosition - 1 ) ; int currentCharacter ; boolean isNewLine = false ; int start = currentTokenStartPosition ; int nextCharacterStart = currentTokenStartPosition ; int previousStart = currentTokenStartPosition ; boolean onFirstColumn = isOnFirstColumn ( start ) ; boolean indentComment = false ; if ( this . indentationLevel != 0 ) { if ( isJavadoc || ! this . formatter . preferences . never_indent_block_comments_on_first_column || ! onFirstColumn ) { indentComment = true ; printIndentationIfNecessary ( ) ; } } if ( this . pendingSpace ) { addInsertEdit ( currentTokenStartPosition , " " ) ; } this . needSpace = false ; this . pendingSpace = false ; int commentColumn = this . column ; if ( includesBlockComments ) { if ( printBlockComment ( currentTokenStartPosition , currentTokenEndPosition ) ) { return ; } } int currentIndentationLevel = this . indentationLevel ; if ( ( commentColumn - 1 ) > this . indentationLevel ) { this . indentationLevel = commentColumn - 1 ; } int currentCommentIndentation = onFirstColumn ? 0 : getCurrentCommentIndentation ( start ) ; boolean formatComment = ( isJavadoc && ( this . formatComments & CodeFormatter . K_JAVA_DOC ) != 0 ) || ( ! isJavadoc && ( this . formatComments & CodeFormatter . K_MULTI_LINE_COMMENT ) != 0 ) ; try { while ( nextCharacterStart <= currentTokenEndPosition && ( currentCharacter = this . scanner . getNextChar ( ) ) != - 1 ) { nextCharacterStart = this . scanner . currentPosition ; switch ( currentCharacter ) { case '\r' : start = previousStart ; isNewLine = true ; if ( this . scanner . getNextChar ( '\n' ) ) { currentCharacter = '\n' ; nextCharacterStart = this . scanner . currentPosition ; } break ; case '\n' : start = previousStart ; isNewLine = true ; nextCharacterStart = this . scanner . currentPosition ; break ; default : if ( isNewLine ) { this . column = 1 ; this . line ++ ; isNewLine = false ; boolean addSpace = false ; if ( onFirstColumn ) { if ( formatComment ) { if ( ScannerHelper . isWhitespace ( ( char ) currentCharacter ) ) { int previousStartPosition = this . scanner . currentPosition ; while ( currentCharacter != - 1 && currentCharacter != '\r' && currentCharacter != '\n' && ScannerHelper . isWhitespace ( ( char ) currentCharacter ) ) { previousStart = nextCharacterStart ; previousStartPosition = this . scanner . currentPosition ; currentCharacter = this . scanner . getNextChar ( ) ; nextCharacterStart = this . scanner . currentPosition ; } if ( currentCharacter == '\r' || currentCharacter == '\n' ) { nextCharacterStart = previousStartPosition ; } } if ( currentCharacter != '\r' && currentCharacter != '\n' ) { addSpace = true ; } } } else { if ( ScannerHelper . isWhitespace ( ( char ) currentCharacter ) ) { int previousStartPosition = this . scanner . currentPosition ; int currentIndentation = 0 ; loop : while ( currentCharacter != - 1 && currentCharacter != '\r' && currentCharacter != '\n' && ScannerHelper . isWhitespace ( ( char ) currentCharacter ) ) { if ( currentIndentation >= currentCommentIndentation ) { break loop ; } previousStart = nextCharacterStart ; previousStartPosition = this . scanner . currentPosition ; switch ( currentCharacter ) { case '\t' : if ( this . tabLength != 0 ) { int reminder = currentIndentation % this . tabLength ; if ( reminder == 0 ) { currentIndentation += this . tabLength ; } else { currentIndentation = ( ( currentIndentation / this . tabLength ) + 1 ) * this . tabLength ; } } break ; default : currentIndentation ++ ; } currentCharacter = this . scanner . getNextChar ( ) ; nextCharacterStart = this . scanner . currentPosition ; } if ( currentCharacter == '\r' || currentCharacter == '\n' ) { nextCharacterStart = previousStartPosition ; } } if ( formatComment ) { int previousStartTemp = previousStart ; int nextCharacterStartTemp = nextCharacterStart ; while ( currentCharacter != - 1 && currentCharacter != '\r' && currentCharacter != '\n' && ScannerHelper . isWhitespace ( ( char ) currentCharacter ) ) { previousStart = nextCharacterStart ; currentCharacter = this . scanner . getNextChar ( ) ; nextCharacterStart = this . scanner . currentPosition ; } if ( currentCharacter == '*' ) { addSpace = true ; } else { previousStart = previousStartTemp ; nextCharacterStart = nextCharacterStartTemp ; } this . scanner . currentPosition = nextCharacterStart ; } } String replacement ; if ( indentComment ) { this . tempBuffer . setLength ( 0 ) ; this . tempBuffer . append ( this . lineSeparator ) ; if ( this . indentationLevel > 0 ) { printIndentationIfNecessary ( this . tempBuffer ) ; } if ( addSpace ) { this . tempBuffer . append ( ' ' ) ; } replacement = this . tempBuffer . toString ( ) ; } else { replacement = addSpace ? this . lineSeparatorAndSpace : this . lineSeparator ; } addReplaceEdit ( start , previousStart - 1 , replacement ) ; } else { this . column += ( nextCharacterStart - previousStart ) ; } } previousStart = nextCharacterStart ; this . scanner . currentPosition = nextCharacterStart ; } } finally { this . indentationLevel = currentIndentationLevel ; } this . lastNumberOfNewLines = 0 ; this . needSpace = false ; this . scanner . resetTo ( currentTokenEndPosition , this . scannerEndPosition - 1 ) ; } private boolean printBlockComment ( int currentTokenStartPosition , int currentTokenEndPosition ) { int maxColumn = this . formatter . preferences . comment_line_length + 1 ; int indentLevel = this . indentationLevel ; int indentations = this . numberOfIndentations ; switch ( this . tabChar ) { case DefaultCodeFormatterOptions . TAB : switch ( this . tabLength ) { case 0 : this . indentationLevel = 0 ; this . column = 1 ; this . numberOfIndentations = 0 ; break ; case 1 : this . indentationLevel = this . column - 1 ; this . numberOfIndentations = this . indentationLevel ; break ; default : this . indentationLevel = ( this . column / this . tabLength ) * this . tabLength ; this . column = this . indentationLevel + 1 ; this . numberOfIndentations = this . indentationLevel / this . tabLength ; } break ; case DefaultCodeFormatterOptions . MIXED : if ( this . tabLength == 0 ) { this . indentationLevel = 0 ; this . column = 1 ; this . numberOfIndentations = 0 ; } else { this . indentationLevel = this . column - 1 ; this . numberOfIndentations = this . indentationLevel / this . tabLength ; } break ; case DefaultCodeFormatterOptions . SPACE : if ( this . indentationSize == 0 ) { this . indentationLevel = 0 ; this . column = 1 ; this . numberOfIndentations = 0 ; } else { this . indentationLevel = this . column - 1 ; } break ; } this . blockCommentBuffer . setLength ( 0 ) ; this . scanner . getNextChar ( ) ; this . scanner . getNextChar ( ) ; this . column += 2 ; this . scanner . skipComments = true ; this . blockCommentTokensBuffer . setLength ( 0 ) ; int editStart = this . scanner . currentPosition ; int editEnd = - 1 ; int previousToken = - 1 ; boolean newLine = false ; boolean multiLines = false ; boolean hasMultiLines = false ; boolean hasTokens = false ; boolean bufferHasTokens = false ; boolean bufferHasNewLine = false ; boolean lineHasTokens = false ; int hasTextOnFirstLine = 0 ; boolean firstWord = true ; boolean clearBlankLines = this . formatter . preferences . comment_clear_blank_lines_in_block_comment ; boolean joinLines = this . formatter . preferences . join_lines_in_comments ; boolean newLinesAtBoundaries = this . formatter . preferences . comment_new_lines_at_block_boundaries ; int scannerLine = Util . getLineNumber ( this . scanner . currentPosition , this . lineEnds , 0 , this . maxLines ) ; int firstLine = scannerLine ; int lineNumber = scannerLine ; int lastTextLine = - 1 ; while ( ! this . scanner . atEnd ( ) ) { int token ; try { token = this . scanner . getNextToken ( ) ; } catch ( InvalidInputException iie ) { token = consumeInvalidToken ( currentTokenEndPosition - 1 ) ; newLine = false ; } boolean insertSpace = ( previousToken == TerminalTokens . TokenNameWHITESPACE ) && ( ! firstWord || ! hasTokens ) ; boolean isTokenStar = false ; switch ( token ) { case TerminalTokens . TokenNameWHITESPACE : if ( this . blockCommentTokensBuffer . length ( ) > 0 ) { if ( hasTextOnFirstLine == 1 && multiLines ) { printBlockCommentHeaderLine ( this . blockCommentBuffer ) ; hasTextOnFirstLine = - 1 ; } this . blockCommentBuffer . append ( this . blockCommentTokensBuffer ) ; this . column += this . blockCommentTokensBuffer . length ( ) ; this . blockCommentTokensBuffer . setLength ( 0 ) ; bufferHasTokens = true ; bufferHasNewLine = false ; } if ( previousToken == - 1 ) { previousToken = SKIP_FIRST_WHITESPACE_TOKEN ; } else { previousToken = token ; } lineNumber = Util . getLineNumber ( this . scanner . currentPosition , this . lineEnds , scannerLine > 1 ? scannerLine - 2 : 0 , this . maxLines ) ; if ( lineNumber > scannerLine ) { hasMultiLines = true ; newLine = true ; } scannerLine = lineNumber ; continue ; case TerminalTokens . TokenNameMULTIPLY : isTokenStar = true ; lineNumber = Util . getLineNumber ( this . scanner . currentPosition , this . lineEnds , scannerLine > 1 ? scannerLine - 2 : 0 , this . maxLines ) ; if ( lineNumber == firstLine && previousToken == SKIP_FIRST_WHITESPACE_TOKEN ) { this . blockCommentBuffer . append ( ' ' ) ; } previousToken = token ; if ( this . scanner . currentCharacter == '/' ) { editEnd = this . scanner . startPosition - 1 ; if ( this . blockCommentTokensBuffer . length ( ) > 0 ) { this . blockCommentBuffer . append ( this . blockCommentTokensBuffer ) ; this . column += this . blockCommentTokensBuffer . length ( ) ; } if ( newLinesAtBoundaries ) { if ( multiLines || hasMultiLines ) { this . blockCommentBuffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( this . blockCommentBuffer ) ; } } this . blockCommentBuffer . append ( ' ' ) ; this . column += BLOCK_FOOTER_LENGTH + 1 ; this . scanner . getNextChar ( ) ; continue ; } if ( newLine ) { scannerLine = lineNumber ; newLine = false ; continue ; } break ; case TerminalTokens . TokenNameMULTIPLY_EQUAL : if ( newLine ) { this . scanner . resetTo ( this . scanner . startPosition , currentTokenEndPosition - 1 ) ; this . scanner . getNextChar ( ) ; previousToken = TerminalTokens . TokenNameMULTIPLY ; scannerLine = Util . getLineNumber ( this . scanner . currentPosition , this . lineEnds , scannerLine > 1 ? scannerLine - 2 : 0 , this . maxLines ) ; continue ; } break ; case TerminalTokens . TokenNameMINUS : case TerminalTokens . TokenNameMINUS_MINUS : if ( previousToken == - 1 ) { this . indentationLevel = indentLevel ; this . numberOfIndentations = indentations ; this . lastNumberOfNewLines = 0 ; this . needSpace = false ; this . scanner . skipComments = false ; this . scanner . resetTo ( currentTokenStartPosition , currentTokenEndPosition - 1 ) ; return false ; } break ; default : break ; } int linesGap ; int max ; lineNumber = Util . getLineNumber ( this . scanner . currentPosition , this . lineEnds , scannerLine > 1 ? scannerLine - 2 : 0 , this . maxLines ) ; if ( lastTextLine == - 1 ) { linesGap = newLinesAtBoundaries ? lineNumber - firstLine : 0 ; max = 0 ; } else { linesGap = lineNumber - lastTextLine ; if ( token == TerminalTokens . TokenNameAT && linesGap == 1 ) { linesGap = 2 ; } max = joinLines && lineHasTokens ? 1 : 0 ; } if ( linesGap > max ) { if ( clearBlankLines ) { if ( token == TerminalTokens . TokenNameAT ) { linesGap = 1 ; } else { linesGap = ( max == 0 || ! joinLines ) ? 1 : 0 ; } } for ( int i = 0 ; i < linesGap ; i ++ ) { if ( this . blockCommentTokensBuffer . length ( ) > 0 ) { if ( hasTextOnFirstLine == 1 ) { printBlockCommentHeaderLine ( this . blockCommentBuffer ) ; hasTextOnFirstLine = - 1 ; } this . blockCommentBuffer . append ( this . blockCommentTokensBuffer ) ; this . blockCommentTokensBuffer . setLength ( 0 ) ; bufferHasTokens = true ; } this . blockCommentBuffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( this . blockCommentBuffer ) ; this . blockCommentBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; firstWord = true ; multiLines = true ; bufferHasNewLine = true ; } insertSpace = insertSpace && linesGap == 0 ; } if ( newLine ) lineHasTokens = false ; int tokenStart = this . scanner . getCurrentTokenStartPosition ( ) ; int tokenLength = ( this . scanner . atEnd ( ) ? this . scanner . eofPosition : this . scanner . currentPosition ) - tokenStart ; hasTokens = true ; if ( ! isTokenStar ) lineHasTokens = true ; if ( hasTextOnFirstLine == 0 && ! isTokenStar ) { if ( firstLine == lineNumber ) { hasTextOnFirstLine = 1 ; this . column ++ ; } else { hasTextOnFirstLine = - 1 ; } } int lastColumn = this . column + this . blockCommentTokensBuffer . length ( ) + tokenLength ; if ( insertSpace ) lastColumn ++ ; if ( lineHasTokens && ! firstWord && lastColumn > maxColumn ) { String tokensString = this . blockCommentTokensBuffer . toString ( ) . trim ( ) ; int tokensStringLength = tokensString . length ( ) ; if ( hasTextOnFirstLine == 1 ) { printBlockCommentHeaderLine ( this . blockCommentBuffer ) ; } if ( ( this . indentationLevel + tokensStringLength + tokenLength ) > maxColumn ) { this . blockCommentBuffer . append ( this . blockCommentTokensBuffer ) ; this . column += this . blockCommentTokensBuffer . length ( ) ; this . blockCommentTokensBuffer . setLength ( 0 ) ; bufferHasNewLine = false ; bufferHasTokens = true ; } if ( bufferHasTokens && ! bufferHasNewLine ) { this . blockCommentBuffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( this . blockCommentBuffer ) ; this . blockCommentBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; } if ( this . blockCommentTokensBuffer . length ( ) > 0 ) { this . blockCommentBuffer . append ( tokensString ) ; this . column += tokensStringLength ; this . blockCommentTokensBuffer . setLength ( 0 ) ; } this . blockCommentBuffer . append ( this . scanner . source , tokenStart , tokenLength ) ; bufferHasTokens = true ; bufferHasNewLine = false ; this . column += tokenLength ; multiLines = true ; hasTextOnFirstLine = - 1 ; } else { if ( insertSpace ) { this . blockCommentTokensBuffer . append ( ' ' ) ; } this . blockCommentTokensBuffer . append ( this . scanner . source , tokenStart , tokenLength ) ; } previousToken = token ; newLine = false ; firstWord = false ; scannerLine = lineNumber ; lastTextLine = lineNumber ; } if ( this . nlsTagCounter == 0 || ! multiLines ) { if ( hasTokens || multiLines ) { StringBuffer replacement ; if ( hasTextOnFirstLine == 1 ) { this . blockCommentTokensBuffer . setLength ( 0 ) ; replacement = this . blockCommentTokensBuffer ; if ( ( hasMultiLines || multiLines ) ) { int col = this . column ; replacement . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( replacement ) ; replacement . append ( BLOCK_LINE_PREFIX ) ; this . column = col ; } else if ( this . blockCommentBuffer . length ( ) == 0 || this . blockCommentBuffer . charAt ( 0 ) != ' ' ) { replacement . append ( ' ' ) ; } replacement . append ( this . blockCommentBuffer ) ; } else { replacement = this . blockCommentBuffer ; } addReplaceEdit ( editStart , editEnd , replacement . toString ( ) ) ; } } this . indentationLevel = indentLevel ; this . numberOfIndentations = indentations ; this . lastNumberOfNewLines = 0 ; this . needSpace = false ; this . scanner . resetTo ( currentTokenEndPosition , this . scannerEndPosition - 1 ) ; this . scanner . skipComments = false ; return true ; } private void printBlockCommentHeaderLine ( StringBuffer buffer ) { if ( ! this . formatter . preferences . comment_new_lines_at_block_boundaries ) { buffer . insert ( 0 , ' ' ) ; this . column ++ ; } else if ( buffer . length ( ) == 0 ) { buffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( buffer ) ; buffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; } else { this . tempBuffer . setLength ( 0 ) ; this . tempBuffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( this . tempBuffer ) ; this . tempBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; buffer . insert ( 0 , this . tempBuffer . toString ( ) ) ; } } public void printEndOfCompilationUnit ( ) { try { int currentTokenStartPosition = this . scanner . currentPosition ; boolean hasComment = false ; boolean hasLineComment = false ; boolean hasWhitespace = false ; int count = 0 ; while ( true ) { this . currentToken = this . scanner . getNextToken ( ) ; switch ( this . currentToken ) { case TerminalTokens . TokenNameWHITESPACE : char [ ] whiteSpaces = this . scanner . getCurrentTokenSource ( ) ; count = 0 ; for ( int i = 0 , max = whiteSpaces . length ; i < max ; i ++ ) { switch ( whiteSpaces [ i ] ) { case '\r' : if ( ( i + 1 ) < max ) { if ( whiteSpaces [ i + 1 ] == '\n' ) { i ++ ; } } count ++ ; break ; case '\n' : count ++ ; } } if ( count == 0 ) { hasWhitespace = true ; addDeleteEdit ( this . scanner . getCurrentTokenStartPosition ( ) , this . scanner . getCurrentTokenEndPosition ( ) ) ; } else if ( hasLineComment ) { preserveEmptyLines ( count , this . scanner . getCurrentTokenStartPosition ( ) ) ; addDeleteEdit ( this . scanner . getCurrentTokenStartPosition ( ) , this . scanner . getCurrentTokenEndPosition ( ) ) ; } else if ( hasComment ) { if ( count == 1 ) { this . printNewLine ( this . scanner . getCurrentTokenStartPosition ( ) ) ; } else { preserveEmptyLines ( count - 1 , this . scanner . getCurrentTokenStartPosition ( ) ) ; } addDeleteEdit ( this . scanner . getCurrentTokenStartPosition ( ) , this . scanner . getCurrentTokenEndPosition ( ) ) ; } else { addDeleteEdit ( this . scanner . getCurrentTokenStartPosition ( ) , this . scanner . getCurrentTokenEndPosition ( ) ) ; } currentTokenStartPosition = this . scanner . currentPosition ; break ; case TerminalTokens . TokenNameCOMMENT_LINE : if ( count >= 1 ) { if ( count > 1 ) { preserveEmptyLines ( count - 1 , this . scanner . getCurrentTokenStartPosition ( ) ) ; } else if ( count == 1 ) { printNewLine ( this . scanner . getCurrentTokenStartPosition ( ) ) ; } } else if ( hasWhitespace ) { space ( ) ; } hasWhitespace = false ; printLineComment ( ) ; currentTokenStartPosition = this . scanner . currentPosition ; hasLineComment = true ; count = 0 ; break ; case TerminalTokens . TokenNameCOMMENT_BLOCK : if ( count >= 1 ) { if ( count > 1 ) { preserveEmptyLines ( count - 1 , this . scanner . getCurrentTokenStartPosition ( ) ) ; } else if ( count == 1 ) { printNewLine ( this . scanner . getCurrentTokenStartPosition ( ) ) ; } } else if ( hasWhitespace ) { space ( ) ; } hasWhitespace = false ; printBlockComment ( false ) ; currentTokenStartPosition = this . scanner . currentPosition ; hasLineComment = false ; hasComment = true ; count = 0 ; break ; case TerminalTokens . TokenNameCOMMENT_JAVADOC : if ( count >= 1 ) { if ( count > 1 ) { preserveEmptyLines ( count - 1 , this . scanner . startPosition ) ; } else if ( count == 1 ) { printNewLine ( this . scanner . startPosition ) ; } } else if ( hasWhitespace ) { space ( ) ; } hasWhitespace = false ; if ( includesJavadocComments ( ) ) { printJavadocComment ( this . scanner . startPosition , this . scanner . currentPosition ) ; } else { printBlockComment ( true ) ; } printNewLine ( ) ; currentTokenStartPosition = this . scanner . currentPosition ; hasLineComment = false ; hasComment = true ; count = 0 ; break ; case TerminalTokens . TokenNameSEMICOLON : print ( this . scanner . currentPosition - this . scanner . startPosition , this . formatter . preferences . insert_space_before_semicolon ) ; break ; case TerminalTokens . TokenNameEOF : if ( count >= 1 || this . formatter . preferences . insert_new_line_at_end_of_file_if_missing ) { this . printNewLine ( this . scannerEndPosition ) ; } return ; default : this . scanner . resetTo ( currentTokenStartPosition , this . scannerEndPosition - 1 ) ; return ; } } } catch ( InvalidInputException e ) { throw new AbortFormatting ( e ) ; } } private void printCodeSnippet ( int startPosition , int endPosition , int linesGap ) { String snippet = new String ( this . scanner . source , startPosition , endPosition - startPosition + 1 ) ; int firstLine = Util . getLineNumber ( startPosition , this . lineEnds , 0 , this . maxLines ) - 1 ; int lastLine = Util . getLineNumber ( endPosition , this . lineEnds , firstLine > 1 ? firstLine - 2 : 0 , this . maxLines ) - 1 ; this . codeSnippetBuffer . setLength ( 0 ) ; if ( firstLine == lastLine && linesGap == 0 ) { this . codeSnippetBuffer . append ( snippet ) ; } else { boolean hasCharsAfterStar = false ; if ( linesGap == 0 ) { this . codeSnippetBuffer . append ( this . scanner . source , startPosition , this . lineEnds [ firstLine ] + 1 - startPosition ) ; firstLine ++ ; } int initialLength = this . codeSnippetBuffer . length ( ) ; for ( int currentLine = firstLine ; currentLine <= lastLine ; currentLine ++ ) { this . scanner . resetTo ( this . lineEnds [ currentLine - 1 ] + 1 , this . lineEnds [ currentLine ] ) ; int lineStart = this . scanner . currentPosition ; boolean hasStar = false ; loop : while ( ! this . scanner . atEnd ( ) ) { char ch = ( char ) this . scanner . getNextChar ( ) ; switch ( ch ) { case ' ' : case '\t' : case ' ' : break ; case '\r' : case '\n' : break loop ; case '*' : hasStar = true ; break loop ; default : if ( ScannerHelper . isWhitespace ( ch ) ) { break ; } break loop ; } } if ( hasStar ) { lineStart = this . scanner . currentPosition ; if ( ! hasCharsAfterStar && ! this . scanner . atEnd ( ) ) { char ch = ( char ) this . scanner . getNextChar ( ) ; boolean atEnd = this . scanner . atEnd ( ) ; switch ( ch ) { case ' ' : case '\t' : case ' ' : break ; case '\r' : case '\n' : atEnd = true ; break ; default : if ( ! ScannerHelper . isWhitespace ( ch ) ) { if ( hasStar ) { hasCharsAfterStar = true ; currentLine = firstLine - 1 ; this . codeSnippetBuffer . setLength ( initialLength ) ; continue ; } } break ; } if ( ! hasCharsAfterStar && ! atEnd ) { lineStart = this . scanner . currentPosition ; } } } int end = currentLine == lastLine ? endPosition : this . lineEnds [ currentLine ] ; this . codeSnippetBuffer . append ( this . scanner . source , lineStart , end + 1 - lineStart ) ; } } HTMLEntity2JavaReader reader = new HTMLEntity2JavaReader ( new StringReader ( this . codeSnippetBuffer . toString ( ) ) ) ; char [ ] buf = new char [ this . codeSnippetBuffer . length ( ) ] ; String convertedSnippet ; try { int read = reader . read ( buf ) ; convertedSnippet = new String ( buf , 0 , read ) ; } catch ( IOException e ) { CommentFormatterUtil . log ( e ) ; return ; } String formattedSnippet = convertedSnippet ; Map options = this . formatter . preferences . getMap ( ) ; if ( this . scanner . sourceLevel > ClassFileConstants . JDK1_3 ) { options . put ( JavaCore . COMPILER_SOURCE , CompilerOptions . versionFromJdkLevel ( this . scanner . sourceLevel ) ) ; } TextEdit edit = CommentFormatterUtil . format2 ( CodeFormatter . K_UNKNOWN | CodeFormatter . F_INCLUDE_COMMENTS , convertedSnippet , 0 , this . lineSeparator , options ) ; if ( edit == null ) { formattedSnippet = this . codeSnippetBuffer . toString ( ) ; } else { formattedSnippet = CommentFormatterUtil . evaluateFormatterEdit ( convertedSnippet , edit , null ) ; Java2HTMLEntityReader javaReader = new Java2HTMLEntityReader ( new StringReader ( formattedSnippet ) ) ; buf = new char [ 256 ] ; this . codeSnippetBuffer . setLength ( 0 ) ; int l ; try { do { l = javaReader . read ( buf ) ; if ( l != - 1 ) this . codeSnippetBuffer . append ( buf , 0 , l ) ; } while ( l > 0 ) ; formattedSnippet = this . codeSnippetBuffer . toString ( ) ; } catch ( IOException e ) { CommentFormatterUtil . log ( e ) ; return ; } } this . codeSnippetBuffer . setLength ( 0 ) ; ILineTracker tracker = new DefaultLineTracker ( ) ; this . column = 1 ; printIndentationIfNecessary ( this . codeSnippetBuffer ) ; this . codeSnippetBuffer . append ( BLOCK_LINE_PREFIX ) ; String linePrefix = this . codeSnippetBuffer . toString ( ) ; this . codeSnippetBuffer . setLength ( 0 ) ; String replacement = formattedSnippet ; tracker . set ( formattedSnippet ) ; int numberOfLines = tracker . getNumberOfLines ( ) ; if ( numberOfLines > 1 ) { int lastLineOffset = - 1 ; for ( int i = 0 ; i < numberOfLines - 1 ; i ++ ) { if ( i > 0 ) this . codeSnippetBuffer . append ( linePrefix ) ; try { lastLineOffset = tracker . getLineOffset ( i + 1 ) ; this . codeSnippetBuffer . append ( formattedSnippet . substring ( tracker . getLineOffset ( i ) , lastLineOffset ) ) ; } catch ( BadLocationException e ) { CommentFormatterUtil . log ( e ) ; return ; } } this . codeSnippetBuffer . append ( linePrefix ) ; this . codeSnippetBuffer . append ( formattedSnippet . substring ( lastLineOffset ) ) ; replacement = this . codeSnippetBuffer . toString ( ) ; } addReplaceEdit ( startPosition , endPosition , replacement ) ; } void printComment ( ) { printComment ( CodeFormatter . K_UNKNOWN , NO_TRAILING_COMMENT , PRESERVE_EMPTY_LINES_KEEP_LAST_NEW_LINES_INDENTATION ) ; } void printComment ( int emptyLinesRules ) { printComment ( CodeFormatter . K_UNKNOWN , NO_TRAILING_COMMENT , emptyLinesRules ) ; } void printComment ( int kind , int trailing ) { printComment ( kind , trailing , PRESERVE_EMPTY_LINES_KEEP_LAST_NEW_LINES_INDENTATION ) ; } void printComment ( int kind , int trailing , int emptyLinesRules ) { final boolean rejectLineComment = kind == CodeFormatter . K_MULTI_LINE_COMMENT || kind == CodeFormatter . K_JAVA_DOC ; final boolean rejectBlockComment = kind == CodeFormatter . K_SINGLE_LINE_COMMENT || kind == CodeFormatter . K_JAVA_DOC ; final boolean rejectJavadocComment = kind == CodeFormatter . K_SINGLE_LINE_COMMENT || kind == CodeFormatter . K_MULTI_LINE_COMMENT ; try { int currentTokenStartPosition = this . scanner . currentPosition ; boolean hasComment = false ; boolean hasLineComment = false ; boolean hasWhitespaces = false ; int lines = 0 ; 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 whitespacesEndPosition = this . scanner . getCurrentTokenEndPosition ( ) ; lines = 0 ; for ( int i = 0 , max = whiteSpaces . length ; i < max ; i ++ ) { switch ( whiteSpaces [ i ] ) { case '\r' : if ( ( i + 1 ) < max ) { if ( whiteSpaces [ i + 1 ] == '\n' ) { i ++ ; } } lines ++ ; break ; case '\n' : lines ++ ; } } boolean realTrailing = trailing > NO_TRAILING_COMMENT ; if ( realTrailing && this . scanner . currentCharacter == '/' && ( lines == 0 || ( lines == 1 && ! hasLineComment && trailing == IMPORT_TRAILING_COMMENT ) ) ) { boolean canChangeTrailing = ( trailing & COMPLEX_TRAILING_COMMENT ) != 0 ; if ( trailing == BASIC_TRAILING_COMMENT && hasLineComment ) { int currentCommentIndentation = getCurrentIndentation ( whiteSpaces , 0 ) ; int relativeIndentation = currentCommentIndentation - this . lastLineComment . currentIndentation ; if ( this . tabLength == 0 ) { canChangeTrailing = relativeIndentation == 0 ; } else { canChangeTrailing = relativeIndentation > - this . tabLength ; } } if ( canChangeTrailing ) { int currentPosition = this . scanner . currentPosition ; if ( this . scanner . getNextToken ( ) == TerminalTokens . TokenNameCOMMENT_LINE ) { realTrailing = ! hasLineComment ; switch ( this . scanner . getNextToken ( ) ) { case TerminalTokens . TokenNameCOMMENT_LINE : realTrailing = false ; break ; case TerminalTokens . TokenNameWHITESPACE : if ( this . scanner . getNextToken ( ) == TerminalTokens . TokenNameCOMMENT_LINE ) { realTrailing = false ; } break ; } } this . scanner . resetTo ( currentPosition , this . scanner . eofPosition - 1 ) ; } } if ( lines > 1 || ( lines == 1 && hasLineComment ) ) { this . lastLineComment . contiguous = false ; } this . lastLineComment . leadingSpaces = whiteSpaces ; this . lastLineComment . lines = lines ; if ( realTrailing ) { if ( hasLineComment ) { if ( lines >= 1 ) { currentTokenStartPosition = tokenStartPosition ; preserveEmptyLines ( lines , currentTokenStartPosition ) ; addDeleteEdit ( currentTokenStartPosition , whitespacesEndPosition ) ; this . scanner . resetTo ( this . scanner . currentPosition , this . scannerEndPosition - 1 ) ; return ; } this . scanner . resetTo ( currentTokenStartPosition , this . scannerEndPosition - 1 ) ; return ; } if ( lines >= 1 ) { if ( hasComment ) { this . printNewLine ( tokenStartPosition ) ; } this . scanner . resetTo ( currentTokenStartPosition , this . scannerEndPosition - 1 ) ; return ; } hasWhitespaces = true ; currentTokenStartPosition = this . scanner . currentPosition ; addDeleteEdit ( tokenStartPosition , whitespacesEndPosition ) ; } else { if ( lines == 0 ) { hasWhitespaces = true ; if ( hasLineComment && emptyLinesRules != PRESERVE_EMPTY_LINES_KEEP_LAST_NEW_LINES_INDENTATION ) { addReplaceEdit ( tokenStartPosition , whitespacesEndPosition , getPreserveEmptyLines ( 0 , emptyLinesRules ) ) ; } else { addDeleteEdit ( tokenStartPosition , whitespacesEndPosition ) ; } } else if ( hasLineComment ) { useAlignmentBreakIndentation ( emptyLinesRules ) ; currentTokenStartPosition = tokenStartPosition ; preserveEmptyLines ( lines , currentTokenStartPosition ) ; addDeleteEdit ( currentTokenStartPosition , whitespacesEndPosition ) ; } else if ( hasComment ) { useAlignmentBreakIndentation ( emptyLinesRules ) ; if ( lines == 1 ) { this . printNewLine ( tokenStartPosition ) ; } else { preserveEmptyLines ( lines - 1 , tokenStartPosition ) ; } 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 ( tokenStartPosition , whitespacesEndPosition , getPreserveEmptyLines ( lines - 1 , emptyLinesRules ) ) ; } else { useAlignmentBreakIndentation ( emptyLinesRules ) ; addDeleteEdit ( tokenStartPosition , whitespacesEndPosition ) ; } } currentTokenStartPosition = this . scanner . currentPosition ; break ; case TerminalTokens . TokenNameCOMMENT_LINE : 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 ( ) ; } } } } if ( rejectLineComment ) break ; if ( lines >= 1 ) { if ( lines > 1 ) { preserveEmptyLines ( lines - 1 , this . scanner . getCurrentTokenStartPosition ( ) ) ; } else if ( lines == 1 ) { printNewLine ( this . scanner . getCurrentTokenStartPosition ( ) ) ; } } else if ( hasWhitespaces ) { space ( ) ; } hasWhitespaces = false ; printLineComment ( ) ; currentTokenStartPosition = this . scanner . currentPosition ; hasLineComment = true ; lines = 0 ; 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 ) { 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 ( ) ; } } } } if ( trailing > NO_TRAILING_COMMENT && lines >= 1 ) { this . scanner . resetTo ( this . scanner . getCurrentTokenStartPosition ( ) , this . scannerEndPosition - 1 ) ; return ; } this . lastLineComment . contiguous = false ; if ( rejectBlockComment ) break ; if ( lines >= 1 ) { if ( lines > 1 ) { preserveEmptyLines ( lines - 1 , this . scanner . getCurrentTokenStartPosition ( ) ) ; } else if ( lines == 1 ) { printNewLine ( this . scanner . getCurrentTokenStartPosition ( ) ) ; } } else if ( hasWhitespaces ) { space ( ) ; } hasWhitespaces = false ; printBlockComment ( false ) ; currentTokenStartPosition = this . scanner . currentPosition ; hasLineComment = false ; hasComment = true ; lines = 0 ; 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 > 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 ( ) ; } } } if ( trailing > NO_TRAILING_COMMENT ) { this . scanner . resetTo ( this . scanner . getCurrentTokenStartPosition ( ) , this . scannerEndPosition - 1 ) ; return ; } this . lastLineComment . contiguous = false ; if ( rejectJavadocComment ) break ; if ( lines >= 1 ) { if ( lines > 1 ) { preserveEmptyLines ( lines - 1 , this . scanner . getCurrentTokenStartPosition ( ) ) ; } else if ( lines == 1 ) { printNewLine ( this . scanner . getCurrentTokenStartPosition ( ) ) ; } } else if ( hasWhitespaces ) { space ( ) ; } hasWhitespaces = false ; if ( includesJavadocComments ( ) ) { printJavadocComment ( this . scanner . startPosition , this . scanner . currentPosition ) ; } else { printBlockComment ( true ) ; } if ( this . useTags && ! this . editsEnabled && foundTaskCount > 0 ) { setEditsEnabled ( foundTaskCount ) ; } printNewLine ( ) ; currentTokenStartPosition = this . scanner . currentPosition ; hasLineComment = false ; hasComment = true ; lines = 0 ; break ; default : this . lastLineComment . contiguous = false ; this . scanner . resetTo ( currentTokenStartPosition , this . scannerEndPosition - 1 ) ; return ; } } } catch ( InvalidInputException e ) { throw new AbortFormatting ( e ) ; } } void printComment ( int kind , String source , int start , int end , int level ) { resetScanner ( source . toCharArray ( ) ) ; this . scanner . resetTo ( start , end ) ; this . numberOfIndentations = level ; this . indentationLevel = level * this . indentationSize ; this . column = this . indentationLevel + 1 ; switch ( kind ) { case CodeFormatter . K_SINGLE_LINE_COMMENT : printComment ( kind , NO_TRAILING_COMMENT ) ; break ; case CodeFormatter . K_MULTI_LINE_COMMENT : printComment ( kind , NO_TRAILING_COMMENT ) ; break ; case CodeFormatter . K_JAVA_DOC : printJavadocComment ( start , end ) ; break ; } } private void printLineComment ( ) { int currentTokenStartPosition = this . scanner . getCurrentTokenStartPosition ( ) ; int currentTokenEndPosition = this . scanner . getCurrentTokenEndPosition ( ) + 1 ; boolean includesLineComments = includesLineComments ( ) ; boolean isNlsTag = false ; if ( CharOperation . indexOf ( Scanner . TAG_PREFIX , this . scanner . source , true , currentTokenStartPosition , currentTokenEndPosition ) != - 1 ) { this . nlsTagCounter = 0 ; isNlsTag = true ; } this . scanner . resetTo ( currentTokenStartPosition , currentTokenEndPosition - 1 ) ; int currentCharacter ; int start = currentTokenStartPosition ; int nextCharacterStart = currentTokenStartPosition ; int commentIndentationLevel ; boolean onFirstColumn = isOnFirstColumn ( start ) ; if ( this . indentationLevel == 0 ) { commentIndentationLevel = this . column - 1 ; } else { if ( onFirstColumn && ( ( includesLineComments && ! this . formatter . preferences . comment_format_line_comment_starting_on_first_column ) || this . formatter . preferences . never_indent_line_comments_on_first_column ) ) { commentIndentationLevel = this . column - 1 ; } else { if ( this . lastLineComment . contiguous ) { int currentCommentIndentation = getCurrentIndentation ( this . lastLineComment . leadingSpaces , 0 ) ; int relativeIndentation = currentCommentIndentation - this . lastLineComment . currentIndentation ; boolean similarCommentsIndentation = false ; if ( this . tabLength == 0 ) { similarCommentsIndentation = relativeIndentation == 0 ; } else if ( relativeIndentation > - this . tabLength ) { similarCommentsIndentation = relativeIndentation == 0 || currentCommentIndentation != 0 && this . lastLineComment . currentIndentation != 0 ; } if ( similarCommentsIndentation && this . lastLineComment . indentation != this . indentationLevel ) { int currentIndentationLevel = this . indentationLevel ; this . indentationLevel = this . lastLineComment . indentation ; printIndentationIfNecessary ( ) ; this . indentationLevel = currentIndentationLevel ; commentIndentationLevel = this . lastLineComment . indentation ; } else { printIndentationIfNecessary ( ) ; commentIndentationLevel = this . column - 1 ; } } else { if ( this . currentAlignment != null && this . currentAlignment . kind == Alignment . ARRAY_INITIALIZER && this . currentAlignment . fragmentCount > 0 && this . indentationLevel < this . currentAlignment . breakIndentationLevel && this . lastLineComment . lines > 0 ) { int currentIndentationLevel = this . indentationLevel ; this . indentationLevel = this . currentAlignment . breakIndentationLevel ; printIndentationIfNecessary ( ) ; this . indentationLevel = currentIndentationLevel ; commentIndentationLevel = this . currentAlignment . breakIndentationLevel ; } else { printIndentationIfNecessary ( ) ; commentIndentationLevel = this . column - 1 ; } } } } this . lastLineComment . contiguous = true ; this . lastLineComment . currentIndentation = getCurrentCommentIndentation ( currentTokenStartPosition ) ; this . lastLineComment . indentation = commentIndentationLevel ; if ( this . pendingSpace ) { if ( this . formatter . preferences . comment_preserve_white_space_between_code_and_line_comments ) { addInsertEdit ( currentTokenStartPosition , new String ( this . lastLineComment . leadingSpaces ) ) ; } else { addInsertEdit ( currentTokenStartPosition , " " ) ; } } this . needSpace = false ; this . pendingSpace = false ; int previousStart = currentTokenStartPosition ; if ( ! isNlsTag && includesLineComments && ( ! onFirstColumn || this . formatter . preferences . comment_format_line_comment_starting_on_first_column ) ) { printLineComment ( currentTokenStartPosition , currentTokenEndPosition - 1 ) ; } else { loop : while ( nextCharacterStart <= currentTokenEndPosition && ( currentCharacter = this . scanner . getNextChar ( ) ) != - 1 ) { nextCharacterStart = this . scanner . currentPosition ; switch ( currentCharacter ) { case '\r' : start = previousStart ; break loop ; case '\n' : start = previousStart ; break loop ; } previousStart = nextCharacterStart ; } if ( start != currentTokenStartPosition ) { addReplaceEdit ( start , currentTokenEndPosition - 1 , this . lineSeparator ) ; this . line ++ ; this . column = 1 ; this . lastNumberOfNewLines = 1 ; } } this . needSpace = false ; this . pendingSpace = false ; if ( this . currentAlignment != null ) { if ( this . memberAlignment != null ) { if ( this . currentAlignment . location . inputOffset > this . memberAlignment . location . inputOffset ) { if ( this . currentAlignment . couldBreak ( ) && this . currentAlignment . wasSplit ) { this . currentAlignment . performFragmentEffect ( ) ; } } else { this . indentationLevel = Math . max ( this . indentationLevel , this . memberAlignment . breakIndentationLevel ) ; } } else if ( this . currentAlignment . couldBreak ( ) && this . currentAlignment . wasSplit ) { this . currentAlignment . performFragmentEffect ( ) ; } if ( this . currentAlignment . kind == Alignment . BINARY_EXPRESSION && this . currentAlignment . enclosing != null && this . currentAlignment . enclosing . kind == Alignment . BINARY_EXPRESSION && this . indentationLevel < this . currentAlignment . breakIndentationLevel ) { this . indentationLevel = this . currentAlignment . breakIndentationLevel ; } } this . scanner . resetTo ( currentTokenEndPosition , this . scannerEndPosition - 1 ) ; } private void printLineComment ( int commentStart , int commentEnd ) { int firstColumn = this . column ; int indentLevel = this . indentationLevel ; int indentations = this . numberOfIndentations ; this . indentationLevel = getNextIndentationLevel ( firstColumn ) ; if ( this . indentationSize != 0 ) { this . numberOfIndentations = this . indentationLevel / this . indentationSize ; } else { this . numberOfIndentations = 0 ; } this . scanner . resetTo ( commentStart , commentEnd ) ; this . scanner . getNextChar ( ) ; this . scanner . getNextChar ( ) ; this . column += 2 ; int maxColumn = this . formatter . preferences . comment_line_length + 1 ; int previousToken = - 1 ; int lastTokenEndPosition = commentStart ; int spaceStartPosition = - 1 ; int spaceEndPosition = - 1 ; this . scanner . skipComments = true ; String newLineString = null ; this . commentIndentation = null ; while ( ! this . scanner . atEnd ( ) ) { int token ; try { token = this . scanner . getNextToken ( ) ; } catch ( InvalidInputException iie ) { token = consumeInvalidToken ( commentEnd ) ; } switch ( token ) { case TerminalTokens . TokenNameWHITESPACE : if ( previousToken == - 1 ) { previousToken = SKIP_FIRST_WHITESPACE_TOKEN ; } else { previousToken = token ; } spaceStartPosition = this . scanner . getCurrentTokenStartPosition ( ) ; spaceEndPosition = this . scanner . getCurrentTokenEndPosition ( ) ; continue ; case TerminalTokens . TokenNameEOF : continue ; case TerminalTokens . TokenNameIdentifier : if ( previousToken == - 1 || previousToken == SKIP_FIRST_WHITESPACE_TOKEN ) { char [ ] identifier = this . scanner . getCurrentTokenSource ( ) ; int startPosition = this . scanner . getCurrentTokenStartPosition ( ) ; int restartPosition = this . scanner . currentPosition ; if ( CharOperation . equals ( identifier , Parser . FALL_THROUGH_TAG , 0 , 5 ) && this . scanner . currentCharacter == '-' ) { try { this . scanner . getNextToken ( ) ; token = this . scanner . getNextToken ( ) ; if ( token == TerminalTokens . TokenNameIdentifier ) { identifier = this . scanner . getCurrentTokenSource ( ) ; if ( CharOperation . endsWith ( Parser . FALL_THROUGH_TAG , identifier ) ) { if ( previousToken == SKIP_FIRST_WHITESPACE_TOKEN ) { addReplaceEdit ( spaceStartPosition , startPosition - 1 , " " ) ; } this . scanner . startPosition = startPosition ; previousToken = token ; break ; } } } catch ( InvalidInputException iie ) { } } this . scanner . startPosition = startPosition ; this . scanner . currentPosition = restartPosition ; } break ; } int tokenStart = this . scanner . getCurrentTokenStartPosition ( ) ; int tokenLength = ( this . scanner . atEnd ( ) ? this . scanner . eofPosition : this . scanner . currentPosition ) - tokenStart ; if ( previousToken == - 1 ) { addInsertEdit ( this . scanner . startPosition , " " ) ; this . column ++ ; } else if ( previousToken == SKIP_FIRST_WHITESPACE_TOKEN ) { addReplaceEdit ( spaceStartPosition , this . scanner . startPosition - 1 , " " ) ; this . column ++ ; spaceStartPosition = - 1 ; } else { boolean insertSpace = previousToken == TerminalTokens . TokenNameWHITESPACE ; if ( insertSpace ) { tokenLength ++ ; } if ( spaceStartPosition > 0 && ( this . column + tokenLength ) > maxColumn ) { this . lastNumberOfNewLines ++ ; this . line ++ ; if ( newLineString == null ) { this . tempBuffer . setLength ( 0 ) ; this . tempBuffer . append ( this . lineSeparator ) ; this . column = 1 ; if ( ! this . formatter . preferences . never_indent_line_comments_on_first_column ) { printIndentationIfNecessary ( this . tempBuffer ) ; } this . tempBuffer . append ( LINE_COMMENT_PREFIX ) ; this . column += LINE_COMMENT_PREFIX_LENGTH ; newLineString = this . tempBuffer . toString ( ) ; firstColumn = this . column ; } else { this . column = firstColumn ; } if ( lastTokenEndPosition > spaceEndPosition ) { this . column += lastTokenEndPosition - ( spaceEndPosition + 1 ) ; } if ( this . edits [ this . editsIndex - 1 ] . offset == spaceStartPosition ) { this . editsIndex -- ; } addReplaceEdit ( spaceStartPosition , spaceEndPosition , newLineString ) ; spaceStartPosition = - 1 ; if ( insertSpace ) { tokenLength -- ; } } else if ( insertSpace ) { addReplaceEdit ( spaceStartPosition , this . scanner . startPosition - 1 , " " ) ; } } this . column += tokenLength ; previousToken = token ; lastTokenEndPosition = this . scanner . currentPosition ; } this . scanner . skipComments = false ; this . indentationLevel = indentLevel ; this . numberOfIndentations = indentations ; this . lastNumberOfNewLines = 0 ; this . scanner . resetTo ( lastTokenEndPosition , commentEnd ) ; while ( ! this . scanner . atEnd ( ) ) { spaceEndPosition = this . scanner . currentPosition ; this . scanner . getNextChar ( ) ; if ( this . scanner . currentCharacter == '\n' || this . scanner . currentCharacter == '\r' ) { this . column = 1 ; this . line ++ ; this . lastNumberOfNewLines ++ ; break ; } } int startReplace = previousToken == SKIP_FIRST_WHITESPACE_TOKEN ? spaceStartPosition : lastTokenEndPosition ; if ( this . column == 1 && commentEnd >= startReplace ) { addReplaceEdit ( startReplace , commentEnd , this . formatter . preferences . line_separator ) ; } } public void printEmptyLines ( int linesNumber ) { this . printEmptyLines ( linesNumber , this . scanner . getCurrentTokenEndPosition ( ) + 1 ) ; } private void printEmptyLines ( int linesNumber , int insertPosition ) { final String buffer = getEmptyLines ( linesNumber ) ; if ( Util . EMPTY_STRING == buffer ) return ; addInsertEdit ( insertPosition , buffer ) ; } void printIndentationIfNecessary ( ) { this . tempBuffer . setLength ( 0 ) ; printIndentationIfNecessary ( this . tempBuffer ) ; if ( this . tempBuffer . length ( ) > 0 ) { addInsertEdit ( this . scanner . getCurrentTokenStartPosition ( ) , this . tempBuffer . toString ( ) ) ; this . pendingSpace = false ; } } private void printIndentationIfNecessary ( StringBuffer buffer ) { switch ( this . tabChar ) { case DefaultCodeFormatterOptions . TAB : boolean useTabsForLeadingIndents = this . useTabsOnlyForLeadingIndents ; int numberOfLeadingIndents = this . numberOfIndentations ; int indentationsAsTab = 0 ; if ( useTabsForLeadingIndents ) { while ( this . column <= this . indentationLevel ) { if ( this . tabLength > 0 && indentationsAsTab < numberOfLeadingIndents ) { if ( buffer != null ) buffer . append ( '\t' ) ; indentationsAsTab ++ ; int complement = this . tabLength - ( ( this . column - 1 ) % this . tabLength ) ; this . column += complement ; } else { if ( buffer != null ) buffer . append ( ' ' ) ; this . column ++ ; } this . needSpace = false ; } } else if ( this . tabLength > 0 ) { while ( this . column <= this . indentationLevel ) { if ( buffer != null ) buffer . append ( '\t' ) ; int complement = this . tabLength - ( ( this . column - 1 ) % this . tabLength ) ; this . column += complement ; this . needSpace = false ; } } break ; case DefaultCodeFormatterOptions . SPACE : while ( this . column <= this . indentationLevel ) { if ( buffer != null ) buffer . append ( ' ' ) ; this . column ++ ; this . needSpace = false ; } break ; case DefaultCodeFormatterOptions . MIXED : useTabsForLeadingIndents = this . useTabsOnlyForLeadingIndents ; numberOfLeadingIndents = this . numberOfIndentations ; indentationsAsTab = 0 ; if ( useTabsForLeadingIndents ) { final int columnForLeadingIndents = numberOfLeadingIndents * this . indentationSize ; while ( this . column <= this . indentationLevel ) { if ( this . column <= columnForLeadingIndents ) { if ( this . tabLength > 0 && ( this . column - 1 + this . tabLength ) <= this . indentationLevel ) { if ( buffer != null ) buffer . append ( '\t' ) ; this . column += this . tabLength ; } else if ( ( this . column - 1 + this . indentationSize ) <= this . indentationLevel ) { for ( int i = 0 , max = this . indentationSize ; i < max ; i ++ ) { if ( buffer != null ) buffer . append ( ' ' ) ; this . column ++ ; } } else { if ( buffer != null ) buffer . append ( ' ' ) ; this . column ++ ; } } else { for ( int i = this . column , max = this . indentationLevel ; i <= max ; i ++ ) { if ( buffer != null ) buffer . append ( ' ' ) ; this . column ++ ; } } this . needSpace = false ; } } else { while ( this . column <= this . indentationLevel ) { if ( this . tabLength > 0 && ( this . column - 1 + this . tabLength ) <= this . indentationLevel ) { if ( buffer != null ) buffer . append ( '\t' ) ; this . column += this . tabLength ; } else if ( this . indentationSize > 0 && ( this . column - 1 + this . indentationSize ) <= this . indentationLevel ) { for ( int i = 0 , max = this . indentationSize ; i < max ; i ++ ) { if ( buffer != null ) buffer . append ( ' ' ) ; this . column ++ ; } } else { if ( buffer != null ) buffer . append ( ' ' ) ; this . column ++ ; } this . needSpace = false ; } } break ; } } private void printJavadocBlock ( FormatJavadocBlock block ) { if ( block == null ) return ; int previousEnd = block . tagEnd ; int maxNodes = block . nodesPtr ; boolean headerLine = block . isHeaderLine ( ) && this . lastNumberOfNewLines == 0 ; int maxColumn = this . formatter . preferences . comment_line_length + 1 ; if ( headerLine ) { maxColumn ++ ; } if ( ! block . isInlined ( ) ) { this . lastNumberOfNewLines = 0 ; } if ( block . isDescription ( ) ) { if ( ! block . isInlined ( ) ) { this . commentIndentation = null ; } } else { int tagLength = previousEnd - block . sourceStart + 1 ; this . column += tagLength ; if ( ! block . isInlined ( ) ) { boolean indentRootTags = this . formatter . preferences . comment_indent_root_tags && ! block . isInDescription ( ) ; int commentIndentationLevel = 0 ; if ( indentRootTags ) { commentIndentationLevel = tagLength + 1 ; boolean indentParamTag = this . formatter . preferences . comment_indent_parameter_description && block . isInParamTag ( ) ; if ( indentParamTag ) { commentIndentationLevel += this . indentationSize ; } } setCommentIndentation ( commentIndentationLevel ) ; } FormatJavadocReference reference = block . reference ; if ( reference != null ) { printJavadocBlockReference ( block , reference ) ; previousEnd = reference . sourceEnd ; } if ( maxNodes < 0 ) { if ( block . isInlined ( ) ) { this . column ++ ; } return ; } } int previousLine = Util . getLineNumber ( previousEnd , this . lineEnds , 0 , this . maxLines ) ; boolean clearBlankLines = this . formatter . preferences . comment_clear_blank_lines_in_javadoc_comment ; boolean joinLines = this . formatter . preferences . join_lines_in_comments ; for ( int i = 0 ; i <= maxNodes ; i ++ ) { FormatJavadocNode node = block . nodes [ i ] ; int nodeStart = node . sourceStart ; int newLines ; if ( i == 0 ) { newLines = this . formatter . preferences . comment_insert_new_line_for_parameter && block . isParamTag ( ) ? 1 : 0 ; if ( nodeStart > ( previousEnd + 1 ) ) { if ( ! clearBlankLines || ! joinLines ) { int startLine = Util . getLineNumber ( nodeStart , this . lineEnds , previousLine - 1 , this . maxLines ) ; int gapLine = previousLine ; if ( joinLines ) gapLine ++ ; if ( startLine > gapLine ) { newLines = startLine - previousLine ; } if ( clearBlankLines ) { if ( newLines > 0 ) newLines = 1 ; } } if ( newLines == 0 && ( ! node . isImmutable ( ) || block . reference != null ) ) { newLines = printJavadocBlockNodesNewLines ( block , node , previousEnd ) ; } if ( block . isImmutable ( ) ) { printJavadocGapLinesForImmutableBlock ( block ) ; } else { printJavadocGapLines ( previousEnd + 1 , nodeStart - 1 , newLines , clearBlankLines , false , null ) ; } } else { this . tempBuffer . setLength ( 0 ) ; if ( newLines > 0 ) { for ( int j = 0 ; j < newLines ; j ++ ) { printJavadocNewLine ( this . tempBuffer ) ; } addInsertEdit ( nodeStart , this . tempBuffer . toString ( ) ) ; } } } else { newLines = this . column > maxColumn ? 1 : 0 ; if ( ! clearBlankLines && node . lineStart > ( previousLine + 1 ) ) newLines = node . lineStart - previousLine ; if ( newLines < node . linesBefore ) newLines = node . linesBefore ; if ( newLines == 0 ) { newLines = printJavadocBlockNodesNewLines ( block , node , previousEnd ) ; } if ( newLines > 0 || nodeStart > ( previousEnd + 1 ) ) { printJavadocGapLines ( previousEnd + 1 , nodeStart - 1 , newLines , clearBlankLines , false , null ) ; } } if ( headerLine && newLines > 0 ) { headerLine = false ; maxColumn -- ; } if ( node . isText ( ) ) { FormatJavadocText text = ( FormatJavadocText ) node ; if ( text . isImmutable ( ) ) { if ( text . isImmutableHtmlTag ( ) && newLines > 0 && this . commentIndentation != null ) { addInsertEdit ( node . sourceStart , this . commentIndentation ) ; this . column += this . commentIndentation . length ( ) ; } printJavadocImmutableText ( text , block , newLines > 0 ) ; this . column += getTextLength ( block , text ) ; } else if ( text . isHtmlTag ( ) ) { printJavadocHtmlTag ( text , block , newLines > 0 ) ; } else { printJavadocText ( text , block , newLines > 0 ) ; } } else { if ( newLines > 0 && this . commentIndentation != null ) { addInsertEdit ( node . sourceStart , this . commentIndentation ) ; this . column += this . commentIndentation . length ( ) ; } printJavadocBlock ( ( FormatJavadocBlock ) node ) ; } previousEnd = node . sourceEnd ; previousLine = Util . getLineNumber ( previousEnd , this . lineEnds , node . lineStart > 1 ? node . lineStart - 2 : 0 , this . maxLines ) ; } this . lastNumberOfNewLines = 0 ; } private int printJavadocBlockNodesNewLines ( FormatJavadocBlock block , FormatJavadocNode node , int previousEnd ) { int maxColumn = this . formatter . preferences . comment_line_length + 1 ; int nodeStart = node . sourceStart ; try { this . scanner . resetTo ( nodeStart , node . sourceEnd ) ; int length = 0 ; boolean newLine = false ; boolean headerLine = block . isHeaderLine ( ) && this . lastNumberOfNewLines == 0 ; int firstColumn = 1 + this . indentationLevel + BLOCK_LINE_PREFIX_LENGTH ; if ( this . commentIndentation != null ) firstColumn += this . commentIndentation . length ( ) ; if ( headerLine ) maxColumn ++ ; FormatJavadocText text = null ; boolean isImmutableNode = node . isImmutable ( ) ; boolean nodeIsText = node . isText ( ) ; if ( nodeIsText ) { text = ( FormatJavadocText ) node ; } else { FormatJavadocBlock inlinedBlock = ( FormatJavadocBlock ) node ; if ( isImmutableNode ) { text = ( FormatJavadocText ) inlinedBlock . getLastNode ( ) ; if ( text != null ) { length += inlinedBlock . tagEnd - inlinedBlock . sourceStart + 1 ; if ( nodeStart > ( previousEnd + 1 ) ) { length ++ ; } this . scanner . resetTo ( text . sourceStart , node . sourceEnd ) ; } } } if ( text != null ) { if ( isImmutableNode ) { if ( nodeStart > ( previousEnd + 1 ) ) { length ++ ; } int lastColumn = this . column + length ; while ( ! this . scanner . atEnd ( ) ) { try { int token = this . scanner . getNextToken ( ) ; switch ( token ) { case TerminalTokens . TokenNameWHITESPACE : if ( CharOperation . indexOf ( '\n' , this . scanner . source , this . scanner . startPosition , this . scanner . currentPosition ) >= 0 ) { return 0 ; } lastColumn = getCurrentIndentation ( this . scanner . getCurrentTokenSource ( ) , lastColumn ) ; break ; case TerminalTokens . TokenNameMULTIPLY : if ( newLine ) { newLine = false ; continue ; } lastColumn ++ ; break ; default : lastColumn += ( this . scanner . atEnd ( ) ? this . scanner . eofPosition : this . scanner . currentPosition ) - this . scanner . startPosition ; break ; } } catch ( InvalidInputException iie ) { lastColumn += ( this . scanner . atEnd ( ) ? this . scanner . eofPosition : this . scanner . currentPosition ) - this . scanner . startPosition ; } if ( lastColumn > maxColumn ) { return 1 ; } } return 0 ; } if ( text . isHtmlTag ( ) ) { if ( text . getHtmlTagID ( ) == JAVADOC_SINGLE_BREAK_TAG_ID ) { return 0 ; } this . scanner . getNextToken ( ) ; if ( this . scanner . getNextToken ( ) == TerminalTokens . TokenNameDIVIDE ) { length ++ ; this . scanner . getNextToken ( ) ; } length += ( this . scanner . atEnd ( ) ? this . scanner . eofPosition : this . scanner . currentPosition ) - this . scanner . startPosition ; this . scanner . getNextToken ( ) ; length ++ ; } else { while ( true ) { int token = this . scanner . getNextToken ( ) ; if ( token == TerminalTokens . TokenNameWHITESPACE || token == TerminalTokens . TokenNameEOF ) break ; int tokenLength = ( this . scanner . atEnd ( ) ? this . scanner . eofPosition : this . scanner . currentPosition ) - this . scanner . startPosition ; length += tokenLength ; if ( ( this . column + length ) >= maxColumn ) { break ; } } } } else { FormatJavadocBlock inlinedBlock = ( FormatJavadocBlock ) node ; length += inlinedBlock . tagEnd - inlinedBlock . sourceStart + 1 ; if ( inlinedBlock . reference != null ) { length ++ ; this . scanner . resetTo ( inlinedBlock . reference . sourceStart , inlinedBlock . reference . sourceEnd ) ; int previousToken = - 1 ; loop : while ( ! this . scanner . atEnd ( ) ) { int token = this . scanner . getNextToken ( ) ; int tokenLength = ( this . scanner . atEnd ( ) ? this . scanner . eofPosition : this . scanner . currentPosition ) - this . scanner . startPosition ; switch ( token ) { case TerminalTokens . TokenNameWHITESPACE : if ( previousToken == TerminalTokens . TokenNameCOMMA ) { length ++ ; } break ; case TerminalTokens . TokenNameMULTIPLY : break ; default : length += tokenLength ; if ( ( this . column + length ) > maxColumn ) { break loop ; } break ; } previousToken = token ; } } length ++ ; } if ( nodeStart > ( previousEnd + 1 ) ) { length ++ ; } if ( ( firstColumn + length ) >= maxColumn && node == block . nodes [ 0 ] ) { return 0 ; } if ( ( this . column + length ) > maxColumn ) { return 1 ; } } catch ( InvalidInputException iie ) { int tokenLength = 1 ; if ( nodeStart > ( previousEnd + 1 ) ) { tokenLength ++ ; } if ( ( this . column + tokenLength ) > maxColumn ) { return 1 ; } } return 0 ; } private void printJavadocBlockReference ( FormatJavadocBlock block , FormatJavadocReference reference ) { int maxColumn = this . formatter . preferences . comment_line_length + 1 ; boolean headerLine = block . isHeaderLine ( ) ; boolean inlined = block . isInlined ( ) ; if ( headerLine ) maxColumn ++ ; this . scanner . resetTo ( block . tagEnd + 1 , reference . sourceEnd ) ; this . javadocBlockRefBuffer . setLength ( 0 ) ; boolean needFormat = false ; int previousToken = - 1 ; int spacePosition = - 1 ; String newLineString = null ; int firstColumn = - 1 ; while ( ! this . scanner . atEnd ( ) ) { int token ; try { token = this . scanner . getNextToken ( ) ; int tokenLength = ( this . scanner . atEnd ( ) ? this . scanner . eofPosition : this . scanner . currentPosition ) - this . scanner . startPosition ; switch ( token ) { case TerminalTokens . TokenNameWHITESPACE : if ( previousToken != - 1 || tokenLength > 1 || this . scanner . currentCharacter != ' ' ) needFormat = true ; switch ( previousToken ) { case TerminalTokens . TokenNameMULTIPLY : case TerminalTokens . TokenNameLPAREN : break ; default : spacePosition = this . javadocBlockRefBuffer . length ( ) ; case - 1 : this . javadocBlockRefBuffer . append ( ' ' ) ; this . column ++ ; break ; } break ; case TerminalTokens . TokenNameMULTIPLY : break ; default : if ( ! inlined && spacePosition > 0 && ( this . column + tokenLength ) > maxColumn ) { this . lastNumberOfNewLines ++ ; this . line ++ ; if ( newLineString == null ) { this . tempBuffer . setLength ( 0 ) ; this . tempBuffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( this . tempBuffer ) ; this . tempBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; if ( this . commentIndentation != null ) { this . tempBuffer . append ( this . commentIndentation ) ; this . column += this . commentIndentation . length ( ) ; } newLineString = this . tempBuffer . substring ( 0 , this . tempBuffer . length ( ) - 1 ) ; firstColumn = this . column ; } else { this . column = firstColumn ; } this . column = firstColumn + this . javadocBlockRefBuffer . length ( ) - spacePosition - 1 ; this . javadocBlockRefBuffer . insert ( spacePosition , newLineString ) ; if ( headerLine ) { headerLine = false ; maxColumn -- ; } spacePosition = - 1 ; } this . javadocBlockRefBuffer . append ( this . scanner . source , this . scanner . startPosition , tokenLength ) ; this . column += tokenLength ; break ; } previousToken = token ; } catch ( InvalidInputException iie ) { } } if ( needFormat ) { addReplaceEdit ( block . tagEnd + 1 , reference . sourceEnd , this . javadocBlockRefBuffer . toString ( ) ) ; } } private int getTextLength ( FormatJavadocBlock block , FormatJavadocText text ) { if ( text . isImmutable ( ) ) { this . scanner . resetTo ( text . sourceStart , text . sourceEnd ) ; int textLength = 0 ; while ( ! this . scanner . atEnd ( ) ) { try { int token = this . scanner . getNextToken ( ) ; if ( token == TerminalTokens . TokenNameWHITESPACE ) { if ( CharOperation . indexOf ( '\n' , this . scanner . source , this . scanner . startPosition , this . scanner . currentPosition ) >= 0 ) { textLength = 0 ; this . scanner . getNextChar ( ) ; if ( this . scanner . currentCharacter == '*' ) { this . scanner . getNextChar ( ) ; if ( this . scanner . currentCharacter != ' ' ) { textLength ++ ; } } else { textLength ++ ; } continue ; } } textLength += ( this . scanner . atEnd ( ) ? this . scanner . eofPosition : this . scanner . currentPosition ) - this . scanner . startPosition ; } catch ( InvalidInputException e ) { textLength += ( this . scanner . atEnd ( ) ? this . scanner . eofPosition : this . scanner . currentPosition ) - this . scanner . startPosition ; } } return textLength ; } if ( block . isOneLineTag ( ) ) { return text . sourceEnd - text . sourceStart + 1 ; } int startLine = Util . getLineNumber ( text . sourceStart , this . lineEnds , 0 , this . maxLines ) ; int endLine = startLine ; int previousEnd = - 1 ; for ( int i = 0 ; i <= text . separatorsPtr ; i ++ ) { int end = ( int ) ( text . separators [ i ] >>> 32 ) ; endLine = Util . getLineNumber ( end , this . lineEnds , endLine - 1 , this . maxLines ) ; if ( endLine > startLine ) { return previousEnd - text . sourceStart + 1 ; } previousEnd = end ; } return text . sourceEnd - text . sourceStart + 1 ; } void printJavadocComment ( int start , int end ) { int lastIndentationLevel = this . indentationLevel ; try { this . scanner . resetTo ( start , end - 1 ) ; if ( ! this . formatterCommentParser . parse ( start , end - 1 ) ) { return ; } FormatJavadoc javadoc = ( FormatJavadoc ) this . formatterCommentParser . docComment ; if ( this . indentationLevel != 0 ) { printIndentationIfNecessary ( ) ; } if ( this . pendingSpace ) { addInsertEdit ( start , " " ) ; } if ( javadoc . blocks == null ) { return ; } this . needSpace = false ; this . pendingSpace = false ; int length = javadoc . blocks . length ; FormatJavadocBlock previousBlock = javadoc . blocks [ 0 ] ; this . lastNumberOfNewLines = 0 ; int currentLine = this . line ; int firstBlockStart = previousBlock . sourceStart ; printIndentationIfNecessary ( null ) ; this . column += JAVADOC_HEADER_LENGTH ; int index = 1 ; if ( length > 1 ) { if ( previousBlock . isDescription ( ) ) { printJavadocBlock ( previousBlock ) ; FormatJavadocBlock block = javadoc . blocks [ index ++ ] ; int newLines = this . formatter . preferences . comment_insert_empty_line_before_root_tags ? 2 : 1 ; printJavadocGapLines ( previousBlock . sourceEnd + 1 , block . sourceStart - 1 , newLines , this . formatter . preferences . comment_clear_blank_lines_in_javadoc_comment , false , null ) ; previousBlock = block ; } while ( index < length ) { printJavadocBlock ( previousBlock ) ; FormatJavadocBlock block = javadoc . blocks [ index ++ ] ; printJavadocGapLines ( previousBlock . sourceEnd + 1 , block . sourceStart - 1 , 1 , this . formatter . preferences . comment_clear_blank_lines_in_javadoc_comment , false , null ) ; previousBlock = block ; } } printJavadocBlock ( previousBlock ) ; int newLines = ( this . formatter . preferences . comment_new_lines_at_javadoc_boundaries && ( this . line > currentLine || javadoc . isMultiLine ( ) ) ) ? 1 : 0 ; printJavadocGapLines ( javadoc . textStart , firstBlockStart - 1 , newLines , this . formatter . preferences . comment_clear_blank_lines_in_javadoc_comment , false , null ) ; printJavadocGapLines ( previousBlock . sourceEnd + 1 , javadoc . textEnd , newLines , this . formatter . preferences . comment_clear_blank_lines_in_javadoc_comment , true , null ) ; } finally { this . scanner . resetTo ( end , this . scannerEndPosition - 1 ) ; this . needSpace = false ; this . indentationLevel = lastIndentationLevel ; this . lastNumberOfNewLines = 0 ; } } private void printJavadocGapLines ( int textStartPosition , int textEndPosition , int newLines , boolean clearBlankLines , boolean footer , StringBuffer output ) { try { if ( newLines == 0 ) { if ( output == null ) { addReplaceEdit ( textStartPosition , textEndPosition , " " ) ; } else { output . append ( ' ' ) ; } this . column ++ ; return ; } if ( textStartPosition > textEndPosition ) { if ( newLines > 0 ) { this . javadocGapLinesBuffer . setLength ( 0 ) ; for ( int i = 0 ; i < newLines ; i ++ ) { this . javadocGapLinesBuffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( this . javadocGapLinesBuffer ) ; if ( footer ) { this . javadocGapLinesBuffer . append ( ' ' ) ; this . column ++ ; } else { this . javadocGapLinesBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; } } if ( output == null ) { addInsertEdit ( textStartPosition , this . javadocGapLinesBuffer . toString ( ) ) ; } else { output . append ( this . javadocGapLinesBuffer ) ; } } return ; } this . scanner . resetTo ( textStartPosition , textEndPosition ) ; this . scanner . recordLineSeparator = true ; this . scanner . linePtr = Util . getLineNumber ( textStartPosition , this . lineEnds , 0 , this . maxLines ) - 2 ; int linePtr = this . scanner . linePtr ; int lineCount = 0 ; int start = textStartPosition ; boolean endsOnMultiply = false ; while ( ! this . scanner . atEnd ( ) ) { switch ( this . scanner . getNextToken ( ) ) { case TerminalTokens . TokenNameMULTIPLY : int linesGap = this . scanner . linePtr - linePtr ; if ( linesGap > 0 ) { this . javadocGapLinesBuffer . setLength ( 0 ) ; if ( lineCount > 0 ) { this . javadocGapLinesBuffer . append ( ' ' ) ; } for ( int i = 0 ; i < linesGap ; i ++ ) { if ( clearBlankLines && lineCount >= newLines ) { if ( textEndPosition >= start ) { if ( output == null ) { addReplaceEdit ( start , textEndPosition , this . javadocGapLinesBuffer . toString ( ) ) ; } else { output . append ( this . javadocGapLinesBuffer ) ; } } return ; } this . javadocGapLinesBuffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( this . javadocGapLinesBuffer ) ; if ( i == ( linesGap - 1 ) ) { this . javadocGapLinesBuffer . append ( ' ' ) ; this . column ++ ; } else { this . javadocGapLinesBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; } lineCount ++ ; } int currentTokenStartPosition = this . scanner . getCurrentTokenStartPosition ( ) ; int tokenLength = this . scanner . currentPosition - currentTokenStartPosition ; if ( output == null ) { addReplaceEdit ( start , currentTokenStartPosition - 1 , this . javadocGapLinesBuffer . toString ( ) ) ; } else { output . append ( this . javadocGapLinesBuffer ) ; output . append ( this . scanner . source , currentTokenStartPosition , tokenLength ) ; } this . column += tokenLength ; if ( footer && clearBlankLines && lineCount == newLines ) { if ( textEndPosition >= currentTokenStartPosition ) { if ( output == null ) { addDeleteEdit ( currentTokenStartPosition , textEndPosition ) ; } } return ; } } start = this . scanner . currentPosition ; linePtr = this . scanner . linePtr ; endsOnMultiply = true ; break ; default : endsOnMultiply = false ; break ; } } if ( lineCount < newLines ) { this . javadocGapLinesBuffer . setLength ( 0 ) ; if ( lineCount > 0 ) { this . javadocGapLinesBuffer . append ( ' ' ) ; } for ( int i = lineCount ; i < newLines - 1 ; i ++ ) { printJavadocNewLine ( this . javadocGapLinesBuffer ) ; } this . javadocGapLinesBuffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( this . javadocGapLinesBuffer ) ; if ( footer ) { this . javadocGapLinesBuffer . append ( ' ' ) ; this . column ++ ; } else { this . javadocGapLinesBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; } if ( output == null ) { if ( textEndPosition >= start ) { addReplaceEdit ( start , textEndPosition , this . javadocGapLinesBuffer . toString ( ) ) ; } else { addInsertEdit ( textEndPosition + 1 , this . javadocGapLinesBuffer . toString ( ) ) ; } } else { output . append ( this . javadocGapLinesBuffer ) ; } } else { if ( textEndPosition >= start ) { this . javadocGapLinesBuffer . setLength ( 0 ) ; if ( this . scanner . linePtr > linePtr ) { if ( lineCount > 0 ) { this . javadocGapLinesBuffer . append ( ' ' ) ; } this . javadocGapLinesBuffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( this . javadocGapLinesBuffer ) ; } this . javadocGapLinesBuffer . append ( ' ' ) ; if ( output == null ) { addReplaceEdit ( start , textEndPosition , this . javadocGapLinesBuffer . toString ( ) ) ; } else { output . append ( this . javadocGapLinesBuffer ) ; } this . needSpace = false ; } else if ( endsOnMultiply ) { if ( output == null ) { addInsertEdit ( textEndPosition + 1 , " " ) ; } else { output . append ( ' ' ) ; } this . needSpace = false ; } this . column ++ ; } } catch ( InvalidInputException iie ) { } finally { this . scanner . recordLineSeparator = false ; this . needSpace = false ; this . scanner . resetTo ( textEndPosition + 1 , this . scannerEndPosition - 1 ) ; this . lastNumberOfNewLines += newLines ; this . line += newLines ; } } private void printJavadocImmutableText ( FormatJavadocText text , FormatJavadocBlock block , boolean textOnNewLine ) { try { int textLineStart = text . lineStart ; this . scanner . tokenizeWhiteSpace = false ; String newLineString = null ; for ( int idx = 0 , max = text . separatorsPtr ; idx <= max ; idx ++ ) { int start = ( int ) text . separators [ idx ] ; int lineStart = Util . getLineNumber ( start , this . lineEnds , textLineStart - 1 , this . maxLines ) ; while ( textLineStart < lineStart ) { int end = this . lineEnds [ textLineStart - 1 ] ; this . scanner . resetTo ( end , start ) ; int token = this . scanner . getNextToken ( ) ; switch ( token ) { case TerminalTokens . TokenNameMULTIPLY : case TerminalTokens . TokenNameMULTIPLY_EQUAL : break ; default : return ; } if ( this . scanner . currentCharacter == ' ' ) { this . scanner . getNextChar ( ) ; } if ( newLineString == null ) { this . tempBuffer . setLength ( 0 ) ; this . column = 1 ; printIndentationIfNecessary ( this . tempBuffer ) ; this . tempBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; newLineString = this . tempBuffer . toString ( ) ; } addReplaceEdit ( end + 1 , this . scanner . getCurrentTokenEndPosition ( ) , newLineString ) ; textLineStart = Util . getLineNumber ( this . scanner . currentPosition - 1 , this . lineEnds , textLineStart , this . maxLines ) ; } } } catch ( InvalidInputException iie ) { } finally { this . needSpace = false ; this . scanner . tokenizeWhiteSpace = true ; this . scanner . resetTo ( text . sourceEnd + 1 , this . scannerEndPosition - 1 ) ; } } private void printJavadocGapLinesForImmutableBlock ( FormatJavadocBlock block ) { int firstLineEnd = - 1 ; int newLineStart = - 1 ; int secondLineStart = - 1 ; int starPosition = - 1 ; int offset = 0 ; int start = block . tagEnd + 1 ; int end = block . nodes [ 0 ] . sourceStart - 1 ; this . scanner . resetTo ( start , end ) ; int lineStart = block . lineStart ; int lineEnd = Util . getLineNumber ( block . nodes [ 0 ] . sourceEnd , this . lineEnds , lineStart - 1 , this . maxLines ) ; boolean multiLinesBlock = lineEnd > ( lineStart + 1 ) ; int previousPosition = this . scanner . currentPosition ; String newLineString = null ; int indentationColumn = 0 ; int leadingSpaces = - 1 ; while ( ! this . scanner . atEnd ( ) ) { char ch = ( char ) this . scanner . getNextChar ( ) ; switch ( ch ) { case '\t' : if ( secondLineStart > 0 || firstLineEnd < 0 ) { int reminder = this . tabLength == 0 ? 0 : offset % this . tabLength ; if ( reminder == 0 ) { offset += this . tabLength ; } else { offset = ( ( offset / this . tabLength ) + 1 ) * this . tabLength ; } } else if ( leadingSpaces >= 0 ) { int reminder = this . tabLength == 0 ? 0 : offset % this . tabLength ; if ( reminder == 0 ) { leadingSpaces += this . tabLength ; } else { leadingSpaces = ( ( offset / this . tabLength ) + 1 ) * this . tabLength ; } } break ; case '\r' : case '\n' : if ( firstLineEnd < 0 ) { firstLineEnd = previousPosition ; } if ( leadingSpaces > 0 && multiLinesBlock ) { if ( newLineString == null ) { this . column = 1 ; this . tempBuffer . setLength ( 0 ) ; printIndentationIfNecessary ( this . tempBuffer ) ; this . tempBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; newLineString = this . tempBuffer . toString ( ) ; indentationColumn = this . column ; } else { this . column = indentationColumn ; } addReplaceEdit ( newLineStart , newLineStart + indentationColumn - 2 , newLineString ) ; } newLineStart = this . scanner . currentPosition ; leadingSpaces = 0 ; starPosition = - 1 ; if ( multiLinesBlock ) { offset = 0 ; secondLineStart = - 1 ; } break ; case '*' : if ( starPosition < 0 && firstLineEnd > 0 ) { secondLineStart = this . scanner . currentPosition ; starPosition = this . scanner . currentPosition ; leadingSpaces = - 1 ; } break ; default : if ( secondLineStart > 0 ) { if ( secondLineStart == starPosition ) { secondLineStart = this . scanner . currentPosition ; } else { if ( offset == 0 && multiLinesBlock ) { if ( newLineString == null ) { this . tempBuffer . setLength ( 0 ) ; this . column = 1 ; printIndentationIfNecessary ( this . tempBuffer ) ; this . tempBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; indentationColumn = this . column ; newLineString = this . tempBuffer . toString ( ) ; } else { this . column = indentationColumn ; } addReplaceEdit ( newLineStart , secondLineStart - 1 , newLineString ) ; } offset ++ ; } } else if ( firstLineEnd < 0 ) { offset ++ ; } else if ( leadingSpaces >= 0 ) { leadingSpaces ++ ; } break ; } previousPosition = this . scanner . currentPosition ; } if ( multiLinesBlock ) { this . column += offset ; } else { this . column ++ ; } if ( ! multiLinesBlock ) { if ( firstLineEnd > 0 ) { addReplaceEdit ( firstLineEnd , end , " " ) ; } } else if ( secondLineStart > 0 ) { if ( newLineString == null ) { this . tempBuffer . setLength ( 0 ) ; this . column = 1 ; printIndentationIfNecessary ( this . tempBuffer ) ; this . tempBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; newLineString = this . tempBuffer . toString ( ) ; indentationColumn = this . column ; } else { this . column = indentationColumn ; } addReplaceEdit ( newLineStart , secondLineStart - 1 , newLineString ) ; } else if ( leadingSpaces > 0 ) { if ( newLineString == null ) { this . tempBuffer . setLength ( 0 ) ; this . column = 1 ; printIndentationIfNecessary ( this . tempBuffer ) ; this . tempBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; newLineString = this . tempBuffer . toString ( ) ; indentationColumn = this . column ; } else { this . column = indentationColumn ; } addReplaceEdit ( newLineStart , newLineStart + indentationColumn - 2 , newLineString ) ; } this . needSpace = false ; this . scanner . resetTo ( end + 1 , this . scannerEndPosition - 1 ) ; } private int printJavadocHtmlTag ( FormatJavadocText text , FormatJavadocBlock block , boolean textOnNewLine ) { boolean clearBlankLines = this . formatter . preferences . comment_clear_blank_lines_in_javadoc_comment ; int textStart = text . sourceStart ; int nextStart = textStart ; int startLine = Util . getLineNumber ( textStart , this . lineEnds , 0 , this . maxLines ) ; int htmlTagID = text . getHtmlTagID ( ) ; if ( text . depth >= this . javadocHtmlTagBuffers . length ) { int length = this . javadocHtmlTagBuffers . length ; System . arraycopy ( this . javadocHtmlTagBuffers , 0 , this . javadocHtmlTagBuffers = new StringBuffer [ text . depth + 6 ] , 0 , length ) ; } StringBuffer buffer = this . javadocHtmlTagBuffers [ text . depth ] ; if ( buffer == null ) { buffer = new StringBuffer ( ) ; this . javadocHtmlTagBuffers [ text . depth ] = buffer ; } else { buffer . setLength ( 0 ) ; } int max = text . separatorsPtr ; int linesAfter = 0 ; int previousEnd = - 1 ; boolean isHtmlBreakTag = htmlTagID == JAVADOC_SINGLE_BREAK_TAG_ID ; boolean isHtmlSeparatorTag = htmlTagID == JAVADOC_SEPARATOR_TAGS_ID ; if ( isHtmlBreakTag ) { return 1 ; } boolean isCode = htmlTagID == JAVADOC_CODE_TAGS_ID ; for ( int idx = 0 , ptr = 0 ; idx <= max || ( text . htmlNodesPtr != - 1 && ptr <= text . htmlNodesPtr ) ; idx ++ ) { int end = ( idx > max ) ? text . sourceEnd : ( int ) ( text . separators [ idx ] >>> 32 ) ; int nodeKind = 0 ; if ( text . htmlNodesPtr >= 0 && ptr <= text . htmlNodesPtr && end > text . htmlNodes [ ptr ] . sourceStart ) { FormatJavadocNode node = text . htmlNodes [ ptr ] ; FormatJavadocText htmlTag = node . isText ( ) ? ( FormatJavadocText ) node : null ; int newLines = htmlTag == null ? 0 : htmlTag . linesBefore ; if ( linesAfter > newLines ) { newLines = linesAfter ; if ( newLines > 1 && clearBlankLines ) { if ( idx < 2 || ( text . htmlIndexes [ idx - 2 ] & JAVADOC_TAGS_ID_MASK ) != JAVADOC_CODE_TAGS_ID ) { newLines = 1 ; } } } if ( textStart < previousEnd ) { addReplaceEdit ( textStart , previousEnd , buffer . toString ( ) ) ; } boolean immutable = node . isImmutable ( ) ; if ( newLines == 0 ) { newLines = printJavadocBlockNodesNewLines ( block , node , previousEnd ) ; } int nodeStart = node . sourceStart ; if ( newLines > 0 || ( idx > 1 && nodeStart > ( previousEnd + 1 ) ) ) { printJavadocGapLines ( previousEnd + 1 , nodeStart - 1 , newLines , clearBlankLines , false , null ) ; } if ( newLines > 0 ) textOnNewLine = true ; buffer . setLength ( 0 ) ; if ( node . isText ( ) ) { if ( immutable ) { if ( textOnNewLine && this . commentIndentation != null ) { addInsertEdit ( node . sourceStart , this . commentIndentation ) ; this . column += this . commentIndentation . length ( ) ; } printJavadocImmutableText ( htmlTag , block , textOnNewLine ) ; this . column += getTextLength ( block , htmlTag ) ; linesAfter = 0 ; } else { linesAfter = printJavadocHtmlTag ( htmlTag , block , textOnNewLine ) ; } nodeKind = 1 ; } else { if ( textOnNewLine && this . commentIndentation != null ) { addInsertEdit ( node . sourceStart , this . commentIndentation ) ; this . column += this . commentIndentation . length ( ) ; } printJavadocBlock ( ( FormatJavadocBlock ) node ) ; linesAfter = 0 ; nodeKind = 2 ; } textStart = node . sourceEnd + 1 ; ptr ++ ; if ( idx > max ) { return linesAfter ; } } else { if ( idx > 0 && linesAfter > 0 ) { printJavadocGapLines ( previousEnd + 1 , nextStart - 1 , linesAfter , clearBlankLines , false , buffer ) ; textOnNewLine = true ; } boolean needIndentation = textOnNewLine ; if ( idx > 0 ) { if ( ! needIndentation && text . isTextAfterHtmlSeparatorTag ( idx - 1 ) ) { needIndentation = true ; } } this . needSpace = idx > 1 && ( previousEnd + 1 ) < nextStart ; printJavadocTextLine ( buffer , nextStart , end , block , idx == 0 , needIndentation , idx == 0 || text . htmlIndexes [ idx - 1 ] != - 1 ) ; linesAfter = 0 ; if ( idx == 0 ) { if ( isHtmlSeparatorTag ) { linesAfter = 1 ; } } else if ( text . htmlIndexes [ idx - 1 ] == JAVADOC_SINGLE_BREAK_TAG_ID ) { linesAfter = 1 ; } } nextStart = ( int ) text . separators [ idx ] ; int endLine = Util . getLineNumber ( end , this . lineEnds , startLine - 1 , this . maxLines ) ; startLine = Util . getLineNumber ( nextStart , this . lineEnds , endLine - 1 , this . maxLines ) ; int linesGap = startLine - endLine ; if ( linesGap > 0 ) { if ( clearBlankLines ) { } else { if ( idx == 0 || linesGap > 1 || ( idx < max && nodeKind == 1 && ( text . htmlIndexes [ idx - 1 ] & JAVADOC_TAGS_ID_MASK ) != JAVADOC_IMMUTABLE_TAGS_ID ) ) { if ( linesAfter < linesGap ) { linesAfter = linesGap ; } } } } textOnNewLine = linesAfter > 0 ; if ( isCode ) { int codeEnd = ( int ) ( text . separators [ max ] >>> 32 ) ; if ( codeEnd > end ) { if ( this . formatter . preferences . comment_format_source ) { if ( textStart < end ) addReplaceEdit ( textStart , end , buffer . toString ( ) ) ; if ( linesGap > 0 ) { int lineStart = this . scanner . getLineStart ( startLine ) ; if ( nextStart > lineStart ) { this . scanner . resetTo ( lineStart , nextStart - 1 ) ; try { int token = this . scanner . getNextToken ( ) ; if ( token == TerminalTokens . TokenNameWHITESPACE ) { token = this . scanner . getNextToken ( ) ; } if ( token == TerminalTokens . TokenNameMULTIPLY ) { nextStart = this . scanner . currentPosition ; } } catch ( InvalidInputException iie ) { } } } int newLines = linesGap ; if ( newLines == 0 ) newLines = 1 ; this . needSpace = false ; printJavadocGapLines ( end + 1 , nextStart - 1 , newLines , false , false , null ) ; printCodeSnippet ( nextStart , codeEnd , linesGap ) ; nextStart = ( int ) text . separators [ max ] ; printJavadocGapLines ( codeEnd + 1 , nextStart - 1 , 1 , false , false , null ) ; return 2 ; } } else { nextStart = ( int ) text . separators [ max ] ; if ( ( nextStart - 1 ) > ( end + 1 ) ) { int line1 = Util . getLineNumber ( end + 1 , this . lineEnds , startLine - 1 , this . maxLines ) ; int line2 = Util . getLineNumber ( nextStart - 1 , this . lineEnds , line1 - 1 , this . maxLines ) ; int gapLines = line2 - line1 - 1 ; printJavadocGapLines ( end + 1 , nextStart - 1 , gapLines , false , false , null ) ; if ( gapLines > 0 ) textOnNewLine = true ; } } return 1 ; } previousEnd = end ; } boolean closingTag = isHtmlBreakTag || ( text . htmlIndexes != null && ( text . htmlIndexes [ max ] & JAVADOC_TAGS_ID_MASK ) == htmlTagID ) ; boolean isValidHtmlSeparatorTag = max > 0 && isHtmlSeparatorTag && closingTag ; if ( previousEnd != - 1 ) { if ( isValidHtmlSeparatorTag ) { if ( linesAfter == 0 ) linesAfter = 1 ; } if ( linesAfter > 0 ) { printJavadocGapLines ( previousEnd + 1 , nextStart - 1 , linesAfter , clearBlankLines , false , buffer ) ; textOnNewLine = linesAfter > 0 ; } } boolean needIndentation = textOnNewLine ; if ( ! needIndentation && ! isHtmlBreakTag && text . htmlIndexes != null && text . isTextAfterHtmlSeparatorTag ( max ) ) { needIndentation = true ; } this . needSpace = ! closingTag && max > 0 && ( previousEnd + 1 ) < nextStart ; printJavadocTextLine ( buffer , nextStart , text . sourceEnd , block , max <= 0 , needIndentation , closingTag ) ; if ( textStart < text . sourceEnd ) { addReplaceEdit ( textStart , text . sourceEnd , buffer . toString ( ) ) ; } this . needSpace = false ; this . scanner . resetTo ( text . sourceEnd + 1 , this . scannerEndPosition - 1 ) ; return isValidHtmlSeparatorTag ? 1 : 0 ; } private void printJavadocNewLine ( StringBuffer buffer ) { buffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( buffer ) ; buffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; this . line ++ ; this . lastNumberOfNewLines ++ ; } private void printJavadocText ( FormatJavadocText text , FormatJavadocBlock block , boolean textOnNewLine ) { boolean clearBlankLines = this . formatter . preferences . comment_clear_blank_lines_in_javadoc_comment ; boolean joinLines = this . formatter . preferences . join_lines_in_comments ; this . javadocTextBuffer . setLength ( 0 ) ; int textStart = text . sourceStart ; int nextStart = textStart ; int startLine = Util . getLineNumber ( textStart , this . lineEnds , 0 , this . maxLines ) ; for ( int idx = 0 , max = text . separatorsPtr ; idx <= max ; idx ++ ) { int end = ( int ) ( text . separators [ idx ] >>> 32 ) ; boolean needIndentation = textOnNewLine ; if ( idx > 0 ) { if ( ! needIndentation && text . isTextAfterHtmlSeparatorTag ( idx - 1 ) ) { needIndentation = true ; } } this . needSpace = idx > 0 ; printJavadocTextLine ( this . javadocTextBuffer , nextStart , end , block , idx == 0 || ( ! joinLines && textOnNewLine ) , needIndentation , false ) ; textOnNewLine = false ; nextStart = ( int ) text . separators [ idx ] ; if ( ! clearBlankLines || ! joinLines ) { int endLine = Util . getLineNumber ( end , this . lineEnds , startLine - 1 , this . maxLines ) ; startLine = Util . getLineNumber ( nextStart , this . lineEnds , endLine - 1 , this . maxLines ) ; int gapLine = endLine ; if ( joinLines ) gapLine ++ ; if ( startLine > gapLine ) { addReplaceEdit ( textStart , end , this . javadocTextBuffer . toString ( ) ) ; textStart = nextStart ; this . javadocTextBuffer . setLength ( 0 ) ; int newLines = startLine - endLine ; if ( clearBlankLines ) newLines = 1 ; printJavadocGapLines ( end + 1 , nextStart - 1 , newLines , this . formatter . preferences . comment_clear_blank_lines_in_javadoc_comment , false , null ) ; textOnNewLine = true ; } else if ( startLine > endLine ) { textOnNewLine = ! joinLines ; } } } boolean needIndentation = textOnNewLine ; this . needSpace = text . separatorsPtr >= 0 ; printJavadocTextLine ( this . javadocTextBuffer , nextStart , text . sourceEnd , block , text . separatorsPtr == - 1 , needIndentation , false ) ; addReplaceEdit ( textStart , text . sourceEnd , this . javadocTextBuffer . toString ( ) ) ; this . needSpace = false ; this . scanner . resetTo ( text . sourceEnd + 1 , this . scannerEndPosition - 1 ) ; } private void printJavadocTextLine ( StringBuffer buffer , int textStart , int textEnd , FormatJavadocBlock block , boolean firstText , boolean needIndentation , boolean isHtmlTag ) { boolean headerLine = block . isHeaderLine ( ) && this . lastNumberOfNewLines == 0 ; this . javadocTokensBuffer . setLength ( 0 ) ; int firstColumn = 1 + this . indentationLevel + BLOCK_LINE_PREFIX_LENGTH ; int maxColumn = this . formatter . preferences . comment_line_length + 1 ; if ( headerLine ) { firstColumn ++ ; maxColumn ++ ; } if ( needIndentation && this . commentIndentation != null ) { buffer . append ( this . commentIndentation ) ; this . column += this . commentIndentation . length ( ) ; firstColumn += this . commentIndentation . length ( ) ; } if ( this . column < firstColumn ) { this . column = firstColumn ; } String newLineString = null ; try { this . scanner . resetTo ( textStart , textEnd ) ; this . scanner . skipComments = true ; int previousToken = - 1 ; boolean textOnNewLine = needIndentation ; while ( ! this . scanner . atEnd ( ) ) { int token ; try { token = this . scanner . getNextToken ( ) ; } catch ( InvalidInputException iie ) { token = consumeInvalidToken ( textEnd ) ; } int tokensBufferLength = this . javadocTokensBuffer . length ( ) ; int tokenStart = this . scanner . getCurrentTokenStartPosition ( ) ; int tokenLength = ( this . scanner . atEnd ( ) ? this . scanner . eofPosition : this . scanner . currentPosition ) - tokenStart ; boolean insertSpace = ( previousToken == TerminalTokens . TokenNameWHITESPACE || this . needSpace ) && ! textOnNewLine ; String tokensBufferString = this . javadocTokensBuffer . toString ( ) . trim ( ) ; switch ( token ) { case TerminalTokens . TokenNameWHITESPACE : if ( tokensBufferLength > 0 ) { boolean shouldSplit = ( this . column + tokensBufferLength ) > maxColumn && ! isHtmlTag && ( insertSpace || tokensBufferLength > 1 ) && tokensBufferString . charAt ( 0 ) != '@' ; if ( shouldSplit ) { this . lastNumberOfNewLines ++ ; this . line ++ ; if ( newLineString == null ) { this . tempBuffer . setLength ( 0 ) ; this . tempBuffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( this . tempBuffer ) ; this . tempBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; if ( this . commentIndentation != null ) { this . tempBuffer . append ( this . commentIndentation ) ; this . column += this . commentIndentation . length ( ) ; } firstColumn = this . column ; newLineString = this . tempBuffer . toString ( ) ; } else { this . column = firstColumn ; } buffer . append ( newLineString ) ; buffer . append ( tokensBufferString ) ; this . column += tokensBufferString . length ( ) ; if ( headerLine ) { firstColumn -- ; maxColumn -- ; headerLine = false ; } } else { buffer . append ( this . javadocTokensBuffer ) ; this . column += tokensBufferLength ; } this . javadocTokensBuffer . setLength ( 0 ) ; } textOnNewLine = false ; previousToken = token ; continue ; case TerminalTokens . TokenNameCharacterLiteral : if ( this . scanner . currentPosition > this . scanner . eofPosition ) { this . scanner . resetTo ( this . scanner . startPosition , textEnd ) ; this . scanner . getNextChar ( ) ; token = 1 ; } break ; } int lastColumn = this . column + tokensBufferLength + tokenLength ; if ( insertSpace ) lastColumn ++ ; boolean shouldSplit = lastColumn > maxColumn && ( ! isHtmlTag || previousToken == - 1 ) && token != TerminalTokens . TokenNameAT && ( tokensBufferLength == 0 || this . javadocTokensBuffer . charAt ( tokensBufferLength - 1 ) != '@' ) ; if ( shouldSplit ) { if ( ( tokensBufferLength > 0 || tokenLength < maxColumn ) && ! isHtmlTag && tokensBufferLength > 0 && ( firstColumn + tokensBufferLength + tokenLength ) >= maxColumn ) { buffer . append ( this . javadocTokensBuffer ) ; this . column += tokensBufferLength ; this . javadocTokensBuffer . setLength ( 0 ) ; tokensBufferLength = 0 ; textOnNewLine = false ; } if ( ( tokensBufferLength > 0 || this . column > firstColumn ) && ( ! textOnNewLine || ! firstText ) ) { this . lastNumberOfNewLines ++ ; this . line ++ ; if ( newLineString == null ) { this . tempBuffer . setLength ( 0 ) ; this . tempBuffer . append ( this . lineSeparator ) ; this . column = 1 ; printIndentationIfNecessary ( this . tempBuffer ) ; this . tempBuffer . append ( BLOCK_LINE_PREFIX ) ; this . column += BLOCK_LINE_PREFIX_LENGTH ; if ( this . commentIndentation != null ) { this . tempBuffer . append ( this . commentIndentation ) ; this . column += this . commentIndentation . length ( ) ; } firstColumn = this . column ; newLineString = this . tempBuffer . toString ( ) ; } else { this . column = firstColumn ; } buffer . append ( newLineString ) ; } if ( tokensBufferLength > 0 ) { String tokensString = tokensBufferString ; buffer . append ( tokensString ) ; this . column += tokensString . length ( ) ; this . javadocTokensBuffer . setLength ( 0 ) ; tokensBufferLength = 0 ; } buffer . append ( this . scanner . source , tokenStart , tokenLength ) ; this . column += tokenLength ; textOnNewLine = false ; if ( headerLine ) { firstColumn -- ; maxColumn -- ; headerLine = false ; } } else { if ( insertSpace ) { this . javadocTokensBuffer . append ( ' ' ) ; } this . javadocTokensBuffer . append ( this . scanner . source , tokenStart , tokenLength ) ; } previousToken = token ; this . needSpace = false ; if ( headerLine && lastColumn == maxColumn && this . scanner . atEnd ( ) ) { this . lastNumberOfNewLines ++ ; this . line ++ ; } } } finally { this . scanner . skipComments = false ; if ( this . javadocTokensBuffer . length ( ) > 0 ) { buffer . append ( this . javadocTokensBuffer ) ; this . column += this . javadocTokensBuffer . length ( ) ; } } } public void printModifiers ( Annotation [ ] annotations , ASTVisitor visitor ) { printModifiers ( annotations , visitor , ICodeFormatterConstants . ANNOTATION_UNSPECIFIED ) ; } public void printModifiers ( Annotation [ ] annotations , ASTVisitor visitor , int annotationSourceKind ) { try { int annotationsLength = annotations != null ? annotations . length : 0 ; int annotationsIndex = 0 ; boolean isFirstModifier = true ; int currentTokenStartPosition = this . scanner . currentPosition ; 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 : case TerminalTokens . TokenNameprivate : case TerminalTokens . TokenNamestatic : case TerminalTokens . TokenNameabstract : case TerminalTokens . TokenNamefinal : case TerminalTokens . TokenNamenative : case TerminalTokens . TokenNamesynchronized : case TerminalTokens . TokenNametransient : case TerminalTokens . TokenNamevolatile : case TerminalTokens . TokenNamestrictfp : hasModifiers = true ; print ( this . scanner . currentPosition - this . scanner . startPosition , ! isFirstModifier ) ; isFirstModifier = false ; currentTokenStartPosition = this . scanner . currentPosition ; break ; case TerminalTokens . TokenNameAT : hasModifiers = true ; if ( ! isFirstModifier ) { space ( ) ; } this . scanner . resetTo ( this . scanner . getCurrentTokenStartPosition ( ) , this . scannerEndPosition - 1 ) ; if ( annotationsIndex < annotationsLength ) { boolean insertSpaceBeforeBrace = this . formatter . preferences . insert_space_before_opening_brace_in_array_initializer ; this . formatter . preferences . insert_space_before_opening_brace_in_array_initializer = false ; try { annotations [ annotationsIndex ++ ] . traverse ( visitor , ( BlockScope ) null ) ; } finally { this . formatter . preferences . insert_space_before_opening_brace_in_array_initializer = insertSpaceBeforeBrace ; } boolean shouldAddNewLine = false ; switch ( annotationSourceKind ) { 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 ; case ICodeFormatterConstants . ANNOTATION_ON_PARAMETER : if ( this . formatter . preferences . insert_new_line_after_annotation_on_parameter ) { shouldAddNewLine = true ; } break ; case ICodeFormatterConstants . ANNOTATION_ON_LOCAL_VARIABLE : if ( this . formatter . preferences . insert_new_line_after_annotation_on_local_variable ) { shouldAddNewLine = true ; } break ; default : } if ( shouldAddNewLine ) { this . printNewLine ( ) ; } } else { return ; } isFirstModifier = false ; currentTokenStartPosition = this . scanner . currentPosition ; break ; case TerminalTokens . TokenNameCOMMENT_BLOCK : case TerminalTokens . TokenNameCOMMENT_JAVADOC : 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 : addDeleteEdit ( this . scanner . getCurrentTokenStartPosition ( ) , this . scanner . getCurrentTokenEndPosition ( ) ) ; int count = 0 ; char [ ] whiteSpaces = this . scanner . getCurrentTokenSource ( ) ; for ( int i = 0 , max = whiteSpaces . length ; i < max ; i ++ ) { switch ( whiteSpaces [ i ] ) { case '\r' : if ( ( i + 1 ) < max ) { if ( whiteSpaces [ i + 1 ] == '\n' ) { i ++ ; } } count ++ ; break ; case '\n' : count ++ ; } } if ( count >= 1 && hasComment ) { printNewLine ( ) ; } currentTokenStartPosition = this . scanner . currentPosition ; hasComment = false ; break ; default : if ( hasModifiers ) { space ( ) ; } this . scanner . resetTo ( currentTokenStartPosition , this . scannerEndPosition - 1 ) ; return ; } } } catch ( InvalidInputException e ) { throw new AbortFormatting ( e ) ; } } public void printNewLine ( ) { this . printNewLine ( this . scanner . getCurrentTokenEndPosition ( ) + 1 ) ; } public void printNewLine ( int insertPosition ) { if ( this . nlsTagCounter > 0 ) { return ; } if ( this . lastNumberOfNewLines >= 1 ) { if ( ! this . preserveLineBreakIndentation ) { this . column = 1 ; } this . preserveLineBreakIndentation = false ; return ; } addInsertEdit ( insertPosition , this . lineSeparator ) ; this . line ++ ; this . lastNumberOfNewLines = 1 ; this . column = 1 ; this . needSpace = false ; this . pendingSpace = false ; this . preserveLineBreakIndentation = false ; this . lastLineComment . contiguous = false ; } private void printNewLinesBeforeDisablingComment ( ) { int linePtr = Arrays . binarySearch ( this . lineEnds , this . scanner . startPosition ) ; if ( linePtr < 0 ) { linePtr = - linePtr - 1 ; } int indentation = 0 ; int beginningOfLine = getLineEnd ( linePtr ) + 1 ; if ( beginningOfLine == - 1 ) { beginningOfLine = 0 ; } OptimizedReplaceEdit currentEdit = this . edits [ this . editsIndex - 1 ] ; int offset = currentEdit . offset ; if ( offset >= beginningOfLine ) return ; int scannerStartPosition = this . scanner . startPosition ; int scannerEofPosition = this . scanner . eofPosition ; int scannerCurrentPosition = this . scanner . currentPosition ; char scannerCurrentChar = this . scanner . currentCharacter ; int length = currentEdit . length ; this . scanner . resetTo ( beginningOfLine , offset + length - 1 ) ; try { while ( ! this . scanner . atEnd ( ) ) { char ch = ( char ) this . scanner . getNextChar ( ) ; switch ( ch ) { case '\t' : if ( this . tabLength != 0 ) { int reminder = indentation % this . tabLength ; if ( reminder == 0 ) { indentation += this . tabLength ; } else { indentation = ( ( indentation / this . tabLength ) + 1 ) * this . tabLength ; } } break ; case ' ' : indentation ++ ; break ; default : return ; } } String indentationString ; int currentIndentation = getCurrentIndentation ( this . scanner . currentPosition ) ; if ( currentIndentation > 0 && this . indentationLevel > 0 ) { int col = this . column ; this . tempBuffer . setLength ( 0 ) ; printIndentationIfNecessary ( this . tempBuffer ) ; indentationString = this . tempBuffer . toString ( ) ; this . column = col ; } else { indentationString = Util . EMPTY_STRING ; } String replacement = currentEdit . replacement ; if ( replacement . length ( ) == 0 ) { this . edits [ this . editsIndex - 1 ] = new OptimizedReplaceEdit ( beginningOfLine , offset + length - beginningOfLine , indentationString ) ; } else { int idx = replacement . lastIndexOf ( this . lineSeparator ) ; if ( idx >= 0 ) { int start = idx + this . lsLength ; this . tempBuffer . setLength ( 0 ) ; this . tempBuffer . append ( replacement . substring ( 0 , start ) ) ; if ( indentationString != Util . EMPTY_STRING ) { this . tempBuffer . append ( indentationString ) ; } this . edits [ this . editsIndex - 1 ] = new OptimizedReplaceEdit ( offset , length , this . tempBuffer . toString ( ) ) ; } } } finally { this . scanner . startPosition = scannerStartPosition ; this . scanner . eofPosition = scannerEofPosition ; this . scanner . currentPosition = scannerCurrentPosition ; this . scanner . currentCharacter = scannerCurrentChar ; } } private boolean printNewLinesCharacters ( int offset , int length ) { boolean foundNewLine = false ; int scannerStartPosition = this . scanner . startPosition ; int scannerEofPosition = this . scanner . eofPosition ; int scannerCurrentPosition = this . scanner . currentPosition ; char scannerCurrentChar = this . scanner . currentCharacter ; this . scanner . resetTo ( offset , offset + length - 1 ) ; try { while ( ! this . scanner . atEnd ( ) ) { int start = this . scanner . currentPosition ; char ch = ( char ) this . scanner . getNextChar ( ) ; boolean needReplace = ch != this . firstLS ; switch ( ch ) { case '\r' : if ( this . scanner . atEnd ( ) ) break ; ch = ( char ) this . scanner . getNextChar ( ) ; if ( ch != '\n' ) break ; needReplace = needReplace || this . lsLength != 2 ; case '\n' : if ( needReplace ) { if ( this . editsIndex == 0 || this . edits [ this . editsIndex - 1 ] . offset != start ) { this . edits [ this . editsIndex ++ ] = new OptimizedReplaceEdit ( start , this . scanner . currentPosition - start , this . lineSeparator ) ; } } foundNewLine = true ; break ; } } } finally { this . scanner . startPosition = scannerStartPosition ; this . scanner . eofPosition = scannerEofPosition ; this . scanner . currentPosition = scannerCurrentPosition ; this . scanner . currentCharacter = scannerCurrentChar ; } return foundNewLine ; } public void printNextToken ( int expectedTokenType ) { printNextToken ( expectedTokenType , false ) ; } public void printNextToken ( int expectedTokenType , boolean considerSpaceIfAny ) { printNextToken ( expectedTokenType , considerSpaceIfAny , PRESERVE_EMPTY_LINES_KEEP_LAST_NEW_LINES_INDENTATION ) ; } public void printNextToken ( int expectedTokenType , boolean considerSpaceIfAny , int emptyLineRules ) { printComment ( CodeFormatter . K_UNKNOWN , NO_TRAILING_COMMENT , emptyLineRules ) ; try { this . currentToken = this . scanner . getNextToken ( ) ; if ( expectedTokenType != this . currentToken ) { throw new AbortFormatting ( "" + expectedTokenType + ", actual:" + this . currentToken ) ; } print ( this . scanner . currentPosition - this . scanner . startPosition , considerSpaceIfAny ) ; } catch ( InvalidInputException e ) { throw new AbortFormatting ( e ) ; } } public void printNextToken ( int [ ] expectedTokenTypes ) { printNextToken ( expectedTokenTypes , false ) ; } public void printNextToken ( int [ ] expectedTokenTypes , boolean considerSpaceIfAny ) { printComment ( CodeFormatter . K_UNKNOWN , NO_TRAILING_COMMENT ) ; try { this . currentToken = this . scanner . getNextToken ( ) ; if ( Arrays . binarySearch ( expectedTokenTypes , this . currentToken ) < 0 ) { StringBuffer expectations = new StringBuffer ( 5 ) ; for ( int i = 0 ; i < expectedTokenTypes . length ; i ++ ) { if ( i > 0 ) { expectations . append ( ',' ) ; } expectations . append ( expectedTokenTypes [ i ] ) ; } throw new AbortFormatting ( "" + expectations . toString ( ) + "], actual:" + this . currentToken ) ; } print ( this . scanner . currentPosition - this . scanner . startPosition , considerSpaceIfAny ) ; } catch ( InvalidInputException e ) { throw new AbortFormatting ( e ) ; } } public void printArrayQualifiedReference ( int numberOfTokens , int sourceEnd ) { int currentTokenStartPosition = this . scanner . currentPosition ; int numberOfIdentifiers = 0 ; try { do { printComment ( CodeFormatter . K_UNKNOWN , NO_TRAILING_COMMENT ) ; switch ( this . currentToken = this . scanner . getNextToken ( ) ) { case TerminalTokens . TokenNameEOF : return ; case TerminalTokens . TokenNameWHITESPACE : addDeleteEdit ( this . scanner . getCurrentTokenStartPosition ( ) , this . scanner . getCurrentTokenEndPosition ( ) ) ; currentTokenStartPosition = this . scanner . currentPosition ; break ; case TerminalTokens . TokenNameCOMMENT_BLOCK : case TerminalTokens . TokenNameCOMMENT_JAVADOC : printBlockComment ( false ) ; currentTokenStartPosition = this . scanner . currentPosition ; break ; case TerminalTokens . TokenNameCOMMENT_LINE : printLineComment ( ) ; currentTokenStartPosition = this . scanner . currentPosition ; break ; case TerminalTokens . TokenNameIdentifier : print ( this . scanner . currentPosition - this . scanner . startPosition , false ) ; currentTokenStartPosition = this . scanner . currentPosition ; if ( ++ numberOfIdentifiers == numberOfTokens ) { this . scanner . resetTo ( currentTokenStartPosition , this . scannerEndPosition - 1 ) ; return ; } break ; case TerminalTokens . TokenNameDOT : print ( this . scanner . currentPosition - this . scanner . startPosition , false ) ; currentTokenStartPosition = this . scanner . currentPosition ; break ; case TerminalTokens . TokenNameRPAREN : currentTokenStartPosition = this . scanner . startPosition ; default : this . scanner . resetTo ( currentTokenStartPosition , this . scannerEndPosition - 1 ) ; return ; } } while ( this . scanner . currentPosition <= sourceEnd ) ; } catch ( InvalidInputException e ) { throw new AbortFormatting ( e ) ; } } public void printQualifiedReference ( int sourceEnd , boolean expectParenthesis ) { int currentTokenStartPosition = this . scanner . currentPosition ; try { do { printComment ( CodeFormatter . K_UNKNOWN , NO_TRAILING_COMMENT ) ; switch ( this . currentToken = this . scanner . getNextToken ( ) ) { case TerminalTokens . TokenNameEOF : return ; case TerminalTokens . TokenNameWHITESPACE : addDeleteEdit ( this . scanner . getCurrentTokenStartPosition ( ) , this . scanner . getCurrentTokenEndPosition ( ) ) ; currentTokenStartPosition = this . scanner . currentPosition ; break ; case TerminalTokens . TokenNameCOMMENT_BLOCK : case TerminalTokens . TokenNameCOMMENT_JAVADOC : printBlockComment ( false ) ; currentTokenStartPosition = this . scanner . currentPosition ; break ; case TerminalTokens . TokenNameCOMMENT_LINE : printLineComment ( ) ; currentTokenStartPosition = this . scanner . currentPosition ; break ; case TerminalTokens . TokenNameIdentifier : case TerminalTokens . TokenNameDOT : print ( this . scanner . currentPosition - this . scanner . startPosition , false ) ; currentTokenStartPosition = this . scanner . currentPosition ; break ; case TerminalTokens . TokenNameRPAREN : if ( expectParenthesis ) { currentTokenStartPosition = this . scanner . startPosition ; } default : this . scanner . resetTo ( currentTokenStartPosition , this . scannerEndPosition - 1 ) ; return ; } } while ( this . scanner . currentPosition <= sourceEnd ) ; } catch ( InvalidInputException e ) { throw new AbortFormatting ( e ) ; } } private void printRule ( StringBuffer stringBuffer ) { for ( int i = 0 ; i < this . pageWidth ; i ++ ) { if ( ( i % this . tabLength ) == 0 ) { stringBuffer . append ( '+' ) ; } else { stringBuffer . append ( '-' ) ; } } stringBuffer . append ( this . lineSeparator ) ; for ( int i = 0 ; i < ( this . pageWidth / this . tabLength ) ; i ++ ) { stringBuffer . append ( i ) ; stringBuffer . append ( '\t' ) ; } } void redoAlignment ( AlignmentException e ) { if ( e . relativeDepth > 0 ) { e . relativeDepth -- ; this . currentAlignment = this . currentAlignment . enclosing ; throw e ; } resetAt ( this . currentAlignment . location ) ; this . scanner . resetTo ( this . currentAlignment . location . inputOffset , this . scanner . eofPosition - 1 ) ; this . currentAlignment . chunkKind = 0 ; } void redoMemberAlignment ( AlignmentException e ) { resetAt ( this . memberAlignment . location ) ; this . scanner . resetTo ( this . memberAlignment . location . inputOffset , this . scanner . eofPosition - 1 ) ; this . memberAlignment . chunkKind = 0 ; } public void reset ( ) { this . checkLineWrapping = true ; this . line = 0 ; this . column = 1 ; this . editsIndex = 0 ; this . nlsTagCounter = 0 ; } private void resetAt ( Location location ) { this . line = location . outputLine ; this . column = location . outputColumn ; this . indentationLevel = location . outputIndentationLevel ; this . numberOfIndentations = location . numberOfIndentations ; this . lastNumberOfNewLines = location . lastNumberOfNewLines ; this . needSpace = location . needSpace ; this . pendingSpace = location . pendingSpace ; this . editsIndex = location . editsIndex ; this . nlsTagCounter = location . nlsTagCounter ; if ( this . editsIndex > 0 ) { this . edits [ this . editsIndex - 1 ] = location . textEdit ; } this . formatter . lastLocalDeclarationSourceStart = location . lastLocalDeclarationSourceStart ; } public void resetScanner ( char [ ] compilationUnitSource ) { this . scanner . setSource ( compilationUnitSource ) ; this . scannerEndPosition = compilationUnitSource . length ; this . scanner . resetTo ( 0 , this . scannerEndPosition - 1 ) ; this . edits = new OptimizedReplaceEdit [ INITIAL_SIZE ] ; this . maxLines = this . lineEnds == null ? - 1 : this . lineEnds . length - 1 ; this . scanner . lineEnds = this . lineEnds ; this . scanner . linePtr = this . maxLines ; initFormatterCommentParser ( ) ; } private void resize ( ) { System . arraycopy ( this . edits , 0 , ( this . edits = new OptimizedReplaceEdit [ this . editsIndex * 2 ] ) , 0 , this . editsIndex ) ; } private void setCommentIndentation ( int commentIndentationLevel ) { if ( commentIndentationLevel == 0 ) { this . commentIndentation = null ; } else { int length = COMMENT_INDENTATIONS . length ; if ( commentIndentationLevel > length ) { System . arraycopy ( COMMENT_INDENTATIONS , 0 , COMMENT_INDENTATIONS = new String [ commentIndentationLevel + 10 ] , 0 , length ) ; } this . commentIndentation = COMMENT_INDENTATIONS [ commentIndentationLevel - 1 ] ; if ( this . commentIndentation == null ) { this . tempBuffer . setLength ( 0 ) ; for ( int i = 0 ; i < commentIndentationLevel ; i ++ ) { this . tempBuffer . append ( ' ' ) ; } this . commentIndentation = this . tempBuffer . toString ( ) ; COMMENT_INDENTATIONS [ commentIndentationLevel - 1 ] = this . commentIndentation ; } } } 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 ; } if ( this . enablingTag != null && CharOperation . equals ( this . scanner . foundTaskTags [ i ] , this . enablingTag ) ) { this . editsEnabled = true ; } } } void setIncludeComments ( boolean on ) { if ( on ) { this . formatComments |= CodeFormatter . F_INCLUDE_COMMENTS ; } else { this . formatComments &= ~ CodeFormatter . F_INCLUDE_COMMENTS ; } } void setHeaderComment ( int position ) { this . headerEndPosition = position ; } public void space ( ) { if ( ! this . needSpace ) return ; this . lastNumberOfNewLines = 0 ; this . pendingSpace = true ; this . column ++ ; this . needSpace = false ; } public String toString ( ) { StringBuffer stringBuffer = new StringBuffer ( ) ; stringBuffer . append ( "" + this . pageWidth + "" ) ; switch ( this . tabChar ) { case DefaultCodeFormatterOptions . TAB : stringBuffer . append ( "TAB" ) ; break ; case DefaultCodeFormatterOptions . SPACE : stringBuffer . append ( "SPACE" ) ; break ; default : stringBuffer . append ( "MIXED" ) ; } stringBuffer . append ( "" + this . tabLength + ")" ) . append ( this . lineSeparator ) . append ( "(line = " + this . line + "" + this . column + "" + this . indentationLevel + ")" ) . append ( this . lineSeparator ) . append ( "" + this . needSpace + "" + this . lastNumberOfNewLines + "" + this . checkLineWrapping + ")" ) . append ( this . lineSeparator ) . append ( "" ) . append ( this . lineSeparator ) ; if ( this . tabLength > 0 ) { printRule ( stringBuffer ) ; } return stringBuffer . toString ( ) ; } public void unIndent ( ) { this . indentationLevel -= this . indentationSize ; this . numberOfIndentations -- ; } } </s>