<s> package org . eclipse . jdt . internal . formatter ; import java . util . HashMap ; import java . util . Map ; import org . eclipse . jdt . core . JavaCore ; import org . eclipse . jdt . core . compiler . ITerminalSymbols ; import org . eclipse . jdt . core . compiler . InvalidInputException ; import org . eclipse . jdt . core . formatter . CodeFormatter ; import org . eclipse . jdt . core . formatter . DefaultCodeFormatterConstants ; import org . eclipse . jdt . internal . compiler . ast . ASTNode ; import org . eclipse . jdt . internal . compiler . ast . CompilationUnitDeclaration ; import org . eclipse . jdt . internal . compiler . ast . ConstructorDeclaration ; import org . eclipse . jdt . internal . compiler . ast . Expression ; import org . eclipse . jdt . internal . compiler . classfmt . ClassFileConstants ; import org . eclipse . jdt . internal . compiler . impl . CompilerOptions ; import org . eclipse . jdt . internal . compiler . parser . Scanner ; 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 . jface . text . IRegion ; import org . eclipse . jface . text . Region ; import org . eclipse . text . edits . TextEdit ; public class DefaultCodeFormatter extends CodeFormatter { public static boolean DEBUG = false ; private static final int K_MASK = K_UNKNOWN | K_EXPRESSION | K_STATEMENTS | K_CLASS_BODY_DECLARATIONS | K_COMPILATION_UNIT | K_SINGLE_LINE_COMMENT | K_MULTI_LINE_COMMENT | K_JAVA_DOC ; private static Scanner PROBING_SCANNER ; private CodeSnippetParsingUtil codeSnippetParsingUtil ; private Map defaultCompilerOptions ; private CodeFormatterVisitor newCodeFormatter ; private Map options ; private DefaultCodeFormatterOptions preferences ; public DefaultCodeFormatter ( ) { this ( new DefaultCodeFormatterOptions ( DefaultCodeFormatterConstants . getJavaConventionsSettings ( ) ) , null ) ; } public DefaultCodeFormatter ( DefaultCodeFormatterOptions preferences ) { this ( preferences , null ) ; } public DefaultCodeFormatter ( DefaultCodeFormatterOptions defaultCodeFormatterOptions , Map options ) { if ( options != null ) { this . options = options ; this . preferences = new DefaultCodeFormatterOptions ( options ) ; } else { this . options = JavaCore . getOptions ( ) ; this . preferences = new DefaultCodeFormatterOptions ( DefaultCodeFormatterConstants . getJavaConventionsSettings ( ) ) ; } this . defaultCompilerOptions = getDefaultCompilerOptions ( ) ; if ( defaultCodeFormatterOptions != null ) { this . preferences . set ( defaultCodeFormatterOptions . getMap ( ) ) ; } } public DefaultCodeFormatter ( Map options ) { this ( null , options ) ; } public String createIndentationString ( final int indentationLevel ) { if ( indentationLevel < 0 ) { throw new IllegalArgumentException ( ) ; } int tabs = 0 ; int spaces = 0 ; switch ( this . preferences . tab_char ) { case DefaultCodeFormatterOptions . SPACE : spaces = indentationLevel * this . preferences . tab_size ; break ; case DefaultCodeFormatterOptions . TAB : tabs = indentationLevel ; break ; case DefaultCodeFormatterOptions . MIXED : int tabSize = this . preferences . tab_size ; if ( tabSize != 0 ) { int spaceEquivalents = indentationLevel * this . preferences . indentation_size ; tabs = spaceEquivalents / tabSize ; spaces = spaceEquivalents % tabSize ; } break ; default : return Util . EMPTY_STRING ; } if ( tabs == 0 && spaces == 0 ) { return Util . EMPTY_STRING ; } StringBuffer buffer = new StringBuffer ( tabs + spaces ) ; for ( int i = 0 ; i < tabs ; i ++ ) { buffer . append ( '\t' ) ; } for ( int i = 0 ; i < spaces ; i ++ ) { buffer . append ( ' ' ) ; } return buffer . toString ( ) ; } public TextEdit format ( int kind , String source , int offset , int length , int indentationLevel , String lineSeparator ) { if ( offset < 0 || length < 0 || length > source . length ( ) ) { throw new IllegalArgumentException ( ) ; } switch ( kind & K_MASK ) { case K_JAVA_DOC : return formatComment ( kind & K_MASK , source , indentationLevel , lineSeparator , new IRegion [ ] { new Region ( offset , length ) } ) ; case K_MULTI_LINE_COMMENT : case K_SINGLE_LINE_COMMENT : return formatComment ( kind & K_MASK , source , indentationLevel , lineSeparator , new IRegion [ ] { new Region ( offset , length ) } ) ; } return format ( kind , source , new IRegion [ ] { new Region ( offset , length ) } , indentationLevel , lineSeparator ) ; } public TextEdit format ( int kind , String source , IRegion [ ] regions , int indentationLevel , String lineSeparator ) { if ( ! regionsSatisfiesPreconditions ( regions , source . length ( ) ) ) { throw new IllegalArgumentException ( ) ; } this . codeSnippetParsingUtil = new CodeSnippetParsingUtil ( ) ; boolean includeComments = ( kind & F_INCLUDE_COMMENTS ) != 0 ; switch ( kind & K_MASK ) { case K_CLASS_BODY_DECLARATIONS : return formatClassBodyDeclarations ( source , indentationLevel , lineSeparator , regions , includeComments ) ; case K_COMPILATION_UNIT : return formatCompilationUnit ( source , indentationLevel , lineSeparator , regions , includeComments ) ; case K_EXPRESSION : return formatExpression ( source , indentationLevel , lineSeparator , regions , includeComments ) ; case K_STATEMENTS : return formatStatements ( source , indentationLevel , lineSeparator , regions , includeComments ) ; case K_UNKNOWN : return probeFormatting ( source , indentationLevel , lineSeparator , regions , includeComments ) ; case K_JAVA_DOC : case K_MULTI_LINE_COMMENT : case K_SINGLE_LINE_COMMENT : throw new IllegalArgumentException ( ) ; } return null ; } private TextEdit formatClassBodyDeclarations ( String source , int indentationLevel , String lineSeparator , IRegion [ ] regions , boolean includeComments ) { ASTNode [ ] bodyDeclarations = this . codeSnippetParsingUtil . parseClassBodyDeclarations ( source . toCharArray ( ) , getDefaultCompilerOptions ( ) , true ) ; if ( bodyDeclarations == null ) { return null ; } return internalFormatClassBodyDeclarations ( source , indentationLevel , lineSeparator , bodyDeclarations , regions , includeComments ) ; } private TextEdit formatComment ( int kind , String source , int indentationLevel , String lineSeparator , IRegion [ ] regions ) { Object oldOption = oldCommentFormatOption ( ) ; boolean isFormattingComments = false ; if ( oldOption == null ) { switch ( kind & K_MASK ) { case K_SINGLE_LINE_COMMENT : isFormattingComments = DefaultCodeFormatterConstants . TRUE . equals ( this . options . get ( DefaultCodeFormatterConstants . FORMATTER_COMMENT_FORMAT_LINE_COMMENT ) ) ; break ; case K_MULTI_LINE_COMMENT : isFormattingComments = DefaultCodeFormatterConstants . TRUE . equals ( this . options . get ( DefaultCodeFormatterConstants . FORMATTER_COMMENT_FORMAT_BLOCK_COMMENT ) ) ; break ; case K_JAVA_DOC : isFormattingComments = DefaultCodeFormatterConstants . TRUE . equals ( this . options . get ( DefaultCodeFormatterConstants . FORMATTER_COMMENT_FORMAT_JAVADOC_COMMENT ) ) ; } } else { isFormattingComments = DefaultCodeFormatterConstants . TRUE . equals ( oldOption ) ; } if ( isFormattingComments ) { if ( lineSeparator != null ) { this . preferences . line_separator = lineSeparator ; } else { this . preferences . line_separator = Util . LINE_SEPARATOR ; } this . preferences . initial_indentation_level = indentationLevel ; if ( this . codeSnippetParsingUtil == null ) this . codeSnippetParsingUtil = new CodeSnippetParsingUtil ( ) ; this . codeSnippetParsingUtil . parseCompilationUnit ( source . toCharArray ( ) , getDefaultCompilerOptions ( ) , true ) ; this . newCodeFormatter = new CodeFormatterVisitor ( this . preferences , this . options , regions , this . codeSnippetParsingUtil , true ) ; IRegion coveredRegion = getCoveredRegion ( regions ) ; int start = coveredRegion . getOffset ( ) ; int end = start + coveredRegion . getLength ( ) ; this . newCodeFormatter . formatComment ( kind , source , start , end , indentationLevel ) ; return this . newCodeFormatter . scribe . getRootEdit ( ) ; } return null ; } private TextEdit formatCompilationUnit ( String source , int indentationLevel , String lineSeparator , IRegion [ ] regions , boolean includeComments ) { CompilationUnitDeclaration compilationUnitDeclaration = this . codeSnippetParsingUtil . parseCompilationUnit ( source . toCharArray ( ) , getDefaultCompilerOptions ( ) , true ) ; if ( lineSeparator != null ) { this . preferences . line_separator = lineSeparator ; } else { this . preferences . line_separator = Util . LINE_SEPARATOR ; } this . preferences . initial_indentation_level = indentationLevel ; this . newCodeFormatter = new CodeFormatterVisitor ( this . preferences , this . options , regions , this . codeSnippetParsingUtil , includeComments ) ; return this . newCodeFormatter . format ( source , compilationUnitDeclaration ) ; } private TextEdit formatExpression ( String source , int indentationLevel , String lineSeparator , IRegion [ ] regions , boolean includeComments ) { Expression expression = this . codeSnippetParsingUtil . parseExpression ( source . toCharArray ( ) , getDefaultCompilerOptions ( ) , true ) ; if ( expression == null ) { return null ; } return internalFormatExpression ( source , indentationLevel , lineSeparator , expression , regions , includeComments ) ; } private TextEdit formatStatements ( String source , int indentationLevel , String lineSeparator , IRegion [ ] regions , boolean includeComments ) { ConstructorDeclaration constructorDeclaration = this . codeSnippetParsingUtil . parseStatements ( source . toCharArray ( ) , getDefaultCompilerOptions ( ) , true , false ) ; if ( constructorDeclaration . statements == null ) { return null ; } return internalFormatStatements ( source , indentationLevel , lineSeparator , constructorDeclaration , regions , includeComments ) ; } private IRegion getCoveredRegion ( IRegion [ ] regions ) { int length = regions . length ; if ( length == 1 ) { return regions [ 0 ] ; } int offset = regions [ 0 ] . getOffset ( ) ; IRegion lastRegion = regions [ length - 1 ] ; return new Region ( offset , lastRegion . getOffset ( ) + lastRegion . getLength ( ) - offset ) ; } public String getDebugOutput ( ) { return this . newCodeFormatter . scribe . toString ( ) ; } private Map getDefaultCompilerOptions ( ) { if ( this . defaultCompilerOptions == null ) { Map optionsMap = new HashMap ( 30 ) ; optionsMap . put ( CompilerOptions . OPTION_LocalVariableAttribute , CompilerOptions . DO_NOT_GENERATE ) ; optionsMap . put ( CompilerOptions . OPTION_LineNumberAttribute , CompilerOptions . DO_NOT_GENERATE ) ; optionsMap . put ( CompilerOptions . OPTION_SourceFileAttribute , CompilerOptions . DO_NOT_GENERATE ) ; optionsMap . put ( CompilerOptions . OPTION_PreserveUnusedLocal , CompilerOptions . PRESERVE ) ; optionsMap . put ( CompilerOptions . OPTION_DocCommentSupport , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportMethodWithConstructorName , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportOverridingPackageDefaultMethod , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportOverridingMethodWithoutSuperInvocation , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportDeprecation , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportDeprecationInDeprecatedCode , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportDeprecationWhenOverridingDeprecatedMethod , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportHiddenCatchBlock , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUnusedLocal , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUnusedObjectAllocation , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUnusedParameter , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUnusedImport , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportSyntheticAccessEmulation , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportNoEffectAssignment , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportNonExternalizedStringLiteral , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportNoImplicitStringConversion , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportNonStaticAccessToStatic , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportIndirectStaticAccess , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportIncompatibleNonInheritedInterfaceMethod , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUnusedPrivateMember , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportLocalVariableHiding , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportFieldHiding , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportPossibleAccidentalBooleanAssignment , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportEmptyStatement , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportAssertIdentifier , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportEnumIdentifier , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUndocumentedEmptyBlock , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUnnecessaryTypeCheck , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportInvalidJavadoc , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportInvalidJavadocTagsVisibility , CompilerOptions . PUBLIC ) ; optionsMap . put ( CompilerOptions . OPTION_ReportInvalidJavadocTags , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportMissingJavadocTagDescription , CompilerOptions . RETURN_TAG ) ; optionsMap . put ( CompilerOptions . OPTION_ReportInvalidJavadocTagsDeprecatedRef , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportInvalidJavadocTagsNotVisibleRef , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportMissingJavadocTags , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportMissingJavadocTagsVisibility , CompilerOptions . PUBLIC ) ; optionsMap . put ( CompilerOptions . OPTION_ReportMissingJavadocTagsOverriding , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportMissingJavadocComments , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportMissingJavadocCommentsVisibility , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportMissingJavadocCommentsOverriding , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportFinallyBlockNotCompletingNormally , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUnusedDeclaredThrownException , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUnusedDeclaredThrownExceptionWhenOverriding , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUnqualifiedFieldAccess , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_Compliance , CompilerOptions . VERSION_1_4 ) ; optionsMap . put ( CompilerOptions . OPTION_TargetPlatform , CompilerOptions . VERSION_1_2 ) ; optionsMap . put ( CompilerOptions . OPTION_TaskTags , Util . EMPTY_STRING ) ; optionsMap . put ( CompilerOptions . OPTION_TaskPriorities , Util . EMPTY_STRING ) ; optionsMap . put ( CompilerOptions . OPTION_TaskCaseSensitive , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUnusedParameterWhenImplementingAbstract , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUnusedParameterWhenOverridingConcrete , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportSpecialParameterHidingField , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportUnavoidableGenericTypeProblems , CompilerOptions . ENABLED ) ; optionsMap . put ( CompilerOptions . OPTION_MaxProblemPerUnit , String . valueOf ( 100 ) ) ; optionsMap . put ( CompilerOptions . OPTION_InlineJsr , CompilerOptions . DISABLED ) ; optionsMap . put ( CompilerOptions . OPTION_ReportMethodCanBeStatic , CompilerOptions . IGNORE ) ; optionsMap . put ( CompilerOptions . OPTION_ReportMethodCanBePotentiallyStatic , CompilerOptions . IGNORE ) ; this . defaultCompilerOptions = optionsMap ; } Object sourceOption = this . options . get ( CompilerOptions . OPTION_Source ) ; if ( sourceOption != null ) { this . defaultCompilerOptions . put ( CompilerOptions . OPTION_Source , sourceOption ) ; } else { this . defaultCompilerOptions . put ( CompilerOptions . OPTION_Source , CompilerOptions . VERSION_1_3 ) ; } return this . defaultCompilerOptions ; } private TextEdit internalFormatClassBodyDeclarations ( String source , int indentationLevel , String lineSeparator , ASTNode [ ] bodyDeclarations , IRegion [ ] regions , boolean includeComments ) { if ( lineSeparator != null ) { this . preferences . line_separator = lineSeparator ; } else { this . preferences . line_separator = Util . LINE_SEPARATOR ; } this . preferences . initial_indentation_level = indentationLevel ; this . newCodeFormatter = new CodeFormatterVisitor ( this . preferences , this . options , regions , this . codeSnippetParsingUtil , includeComments ) ; return this . newCodeFormatter . format ( source , bodyDeclarations ) ; } private TextEdit internalFormatExpression ( String source , int indentationLevel , String lineSeparator , Expression expression , IRegion [ ] regions , boolean includeComments ) { if ( lineSeparator != null ) { this . preferences . line_separator = lineSeparator ; } else { this . preferences . line_separator = Util . LINE_SEPARATOR ; } this . preferences . initial_indentation_level = indentationLevel ; this . newCodeFormatter = new CodeFormatterVisitor ( this . preferences , this . options , regions , this . codeSnippetParsingUtil , includeComments ) ; TextEdit textEdit = this . newCodeFormatter . format ( source , expression ) ; return textEdit ; } private TextEdit internalFormatStatements ( String source , int indentationLevel , String lineSeparator , ConstructorDeclaration constructorDeclaration , IRegion [ ] regions , boolean includeComments ) { if ( lineSeparator != null ) { this . preferences . line_separator = lineSeparator ; } else { this . preferences . line_separator = Util . LINE_SEPARATOR ; } this . preferences . initial_indentation_level = indentationLevel ; this . newCodeFormatter = new CodeFormatterVisitor ( this . preferences , this . options , regions , this . codeSnippetParsingUtil , includeComments ) ; return this . newCodeFormatter . format ( source , constructorDeclaration ) ; } private Object oldCommentFormatOption ( ) { return this . options . get ( DefaultCodeFormatterConstants . FORMATTER_COMMENT_FORMAT ) ; } private TextEdit probeFormatting ( String source , int indentationLevel , String lineSeparator , IRegion [ ] regions , boolean includeComments ) { if ( PROBING_SCANNER == null ) { PROBING_SCANNER = new Scanner ( true , false , false , ClassFileConstants . JDK1_6 , ClassFileConstants . JDK1_6 , null , null , true ) ; } PROBING_SCANNER . setSource ( source . toCharArray ( ) ) ; IRegion coveredRegion = getCoveredRegion ( regions ) ; int offset = coveredRegion . getOffset ( ) ; int length = coveredRegion . getLength ( ) ; PROBING_SCANNER . resetTo ( offset , offset + length - 1 ) ; try { int kind = - 1 ; switch ( PROBING_SCANNER . getNextToken ( ) ) { case ITerminalSymbols . TokenNameCOMMENT_BLOCK : if ( PROBING_SCANNER . getNextToken ( ) == TerminalTokens . TokenNameEOF ) { kind = K_MULTI_LINE_COMMENT ; } break ; case ITerminalSymbols . TokenNameCOMMENT_LINE : if ( PROBING_SCANNER . getNextToken ( ) == TerminalTokens . TokenNameEOF ) { kind = K_SINGLE_LINE_COMMENT ; } break ; case ITerminalSymbols . TokenNameCOMMENT_JAVADOC : if ( PROBING_SCANNER . getNextToken ( ) == TerminalTokens . TokenNameEOF ) { kind = K_JAVA_DOC ; } break ; } if ( kind != - 1 ) { return formatComment ( kind , source , indentationLevel , lineSeparator , regions ) ; } } catch ( InvalidInputException e ) { } PROBING_SCANNER . setSource ( ( char [ ] ) null ) ; Expression expression = this . codeSnippetParsingUtil . parseExpression ( source . toCharArray ( ) , getDefaultCompilerOptions ( ) , true ) ; if ( expression != null ) { return internalFormatExpression ( source , indentationLevel , lineSeparator , expression , regions , includeComments ) ; } ASTNode [ ] bodyDeclarations = this . codeSnippetParsingUtil . parseClassBodyDeclarations ( source . toCharArray ( ) , getDefaultCompilerOptions ( ) , true ) ; if ( bodyDeclarations != null ) { return internalFormatClassBodyDeclarations ( source , indentationLevel , lineSeparator , bodyDeclarations , regions , includeComments ) ; } ConstructorDeclaration constructorDeclaration = this . codeSnippetParsingUtil . parseStatements ( source . toCharArray ( ) , getDefaultCompilerOptions ( ) , true , false ) ; if ( constructorDeclaration . statements != null ) { return internalFormatStatements ( source , indentationLevel , lineSeparator , constructorDeclaration , regions , includeComments ) ; } return formatCompilationUnit ( source , indentationLevel , lineSeparator , regions , includeComments ) ; } private boolean regionsSatisfiesPreconditions ( IRegion [ ] regions , int maxLength ) { int regionsLength = regions == null ? 0 : regions . length ; if ( regionsLength == 0 ) { return false ; } IRegion first = regions [ 0 ] ; if ( first . getOffset ( ) < 0 || first . getLength ( ) < 0 || first . getOffset ( ) + first . getLength ( ) > maxLength ) { return false ; } int lastOffset = first . getOffset ( ) + first . getLength ( ) - 1 ; for ( int i = 1 ; i < regionsLength ; i ++ ) { IRegion current = regions [ i ] ; if ( lastOffset > current . getOffset ( ) ) { return false ; } if ( current . getOffset ( ) < 0 || current . getLength ( ) < 0 || current . getOffset ( ) + current . getLength ( ) > maxLength ) { return false ; } lastOffset = current . getOffset ( ) + current . getLength ( ) - 1 ; } return true ; } } </s>