| /******************************************************************************* |
| * Copyright (c) 2000, 2011 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * $Id: DefaultCodeFormatter.java 23290 2010-01-22 18:20:54Z stephan $ |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Fraunhofer FIRST - extended API and implementation |
| * Technical University Berlin - extended API and implementation |
| *******************************************************************************/ |
| 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 { |
| |
| /** |
| * Debug trace |
| */ |
| public static boolean DEBUG = false; |
| |
| // Mask for code formatter kinds |
| private static final int K_MASK = K_UNKNOWN |
| | K_EXPRESSION |
| | K_STATEMENTS |
| //{ObjectTeams: another root node for parsing/formatting: |
| | K_PARAMETER_MAPPING |
| // SH} |
| | K_CLASS_BODY_DECLARATIONS |
| | K_COMPILATION_UNIT |
| | K_SINGLE_LINE_COMMENT |
| | K_MULTI_LINE_COMMENT |
| | K_JAVA_DOC; |
| |
| // Scanner use to probe the kind of the source given to the formatter |
| 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(); |
| } |
| |
| /** |
| * @see org.eclipse.jdt.core.formatter.CodeFormatter#format(int, java.lang.String, int, int, int, java.lang.String) |
| */ |
| 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 : |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=102780 |
| // use the integrated comment formatter to format comment |
| return formatComment(kind & K_MASK, source, indentationLevel, lineSeparator, new IRegion[] {new Region(offset, length)}); |
| // $FALL-THROUGH$ - fall through next case when old comment formatter is activated |
| 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); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| 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); |
| //{ObjectTeams: Parameter mappinmg is not handled by formatExpression because of separate parser method "parseParameterMapping" to parse snippets |
| case K_PARAMETER_MAPPING : |
| return formatParameterMapping(source, indentationLevel, lineSeparator, regions, includeComments); |
| //jsv} |
| case K_UNKNOWN : |
| return probeFormatting(source, indentationLevel, lineSeparator, regions, includeComments); |
| case K_JAVA_DOC : |
| case K_MULTI_LINE_COMMENT : |
| case K_SINGLE_LINE_COMMENT : |
| //https://bugs.eclipse.org/bugs/show_bug.cgi?id=204091 |
| 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) { |
| // a problem occurred while parsing the source |
| return null; |
| } |
| return internalFormatClassBodyDeclarations(source, indentationLevel, lineSeparator, bodyDeclarations, regions, includeComments); |
| } |
| |
| /* |
| * Format a javadoc comment. |
| * Since bug 102780 this is done by a specific method when new javadoc formatter is activated. |
| */ |
| 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) { |
| // a problem occurred while parsing the source |
| return null; |
| } |
| return internalFormatExpression(source, indentationLevel, lineSeparator, expression, regions, includeComments); |
| } |
| |
| //{ObjectTeams: separate Method to format ParameterMappings |
| private TextEdit formatParameterMapping(String source, int indentationLevel, String lineSeparator, IRegion[] regions, boolean includeComments) { |
| Expression expression = this.codeSnippetParsingUtil.parseParameterMapping(source.toCharArray(), getDefaultCompilerOptions(), true); |
| |
| if (expression == null) { |
| // a problem occured while parsing the source |
| return null; |
| } |
| // We do not need an own internalFormatParameterMapping method, because parseParameterMapping returns an Expression |
| return internalFormatExpression(source, indentationLevel, lineSeparator, expression, regions, includeComments); |
| } |
| //jsv} |
| |
| 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) { |
| // a problem occured while parsing the source |
| 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(); |
| } |
| |
| //{ObjectTeams: be nice: |
| @SuppressWarnings("unchecked") |
| // SH} |
| 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); |
| //{ObjectTeams: |
| optionsMap.put(CompilerOptions.OPTION_Decapsulation, CompilerOptions.REPORT_BINDING); |
| |
| optionsMap.put(CompilerOptions.OPTION_ReportNotExactlyOneBasecall, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportBaseclassCycle, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportUnsafeRoleInstantiation, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportFragileCallin, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportPotentialAmbiguousPlayedby, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportAbstractPotentialRelevantRole, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportDecapsulation, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportDecapsulationWrite, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportDeprecatedPathSyntax, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportInferredCallout, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportWeaveIntoSystemClass, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportOverrideFinalRole, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportExceptionInGuard, CompilerOptions.IGNORE); |
| optionsMap.put(CompilerOptions.OPTION_ReportAmbiguousLowering, CompilerOptions.IGNORE); |
| // SH} |
| 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_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); |
| } |
| //{ObjectTeams: OT-defaults: |
| // support formatting non-OT/J code: |
| Object otjOption = this.options.get(CompilerOptions.OPTION_AllowScopedKeywords); |
| if (otjOption != null) |
| this.defaultCompilerOptions.put(CompilerOptions.OPTION_AllowScopedKeywords, otjOption); |
| Object javaOption = this.options.get(CompilerOptions.OPTION_PureJavaOnly); |
| if (javaOption != null) |
| this.defaultCompilerOptions.put(CompilerOptions.OPTION_PureJavaOnly, javaOption); |
| // SH} |
| 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); |
| } |
| |
| /** |
| * Deprecated as using old option constant |
| * @deprecated |
| */ |
| 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) { |
| // scanner use to check if the kind could be K_JAVA_DOC, K_MULTI_LINE_COMMENT or K_SINGLE_LINE_COMMENT |
| // do not tokenize white spaces to get single comments even with spaces before... |
| PROBING_SCANNER = new Scanner(true, false/*do not tokenize whitespaces*/, false/*nls*/, ClassFileConstants.JDK1_6, ClassFileConstants.JDK1_6, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/); |
| } |
| 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) { |
| // ignore |
| } |
| PROBING_SCANNER.setSource((char[]) null); |
| |
| // probe for expression |
| Expression expression = this.codeSnippetParsingUtil.parseExpression(source.toCharArray(), getDefaultCompilerOptions(), true); |
| if (expression != null) { |
| return internalFormatExpression(source, indentationLevel, lineSeparator, expression, regions, includeComments); |
| } |
| |
| // probe for body declarations (fields, methods, constructors) |
| ASTNode[] bodyDeclarations = this.codeSnippetParsingUtil.parseClassBodyDeclarations(source.toCharArray(), getDefaultCompilerOptions(), true); |
| if (bodyDeclarations != null) { |
| return internalFormatClassBodyDeclarations(source, indentationLevel, lineSeparator, bodyDeclarations, regions, includeComments); |
| } |
| |
| // probe for statements |
| ConstructorDeclaration constructorDeclaration = this.codeSnippetParsingUtil.parseStatements(source.toCharArray(), getDefaultCompilerOptions(), true, false); |
| if (constructorDeclaration.statements != null) { |
| return internalFormatStatements(source, indentationLevel, lineSeparator, constructorDeclaration, regions, includeComments); |
| } |
| |
| // this has to be a compilation unit |
| return formatCompilationUnit(source, indentationLevel, lineSeparator, regions, includeComments); |
| } |
| |
| /** |
| * True if |
| * 1. All regions are within maxLength |
| * 2. regions are sorted |
| * 3. regions are not overlapping |
| */ |
| 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; |
| } |
| } |