| /******************************************************************************* |
| * Copyright (c) 2000, 2018 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.core.dom.rewrite; |
| |
| import java.util.ArrayList; |
| import java.util.IdentityHashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Stack; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.jdt.core.dom.*; |
| import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer; |
| import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer.SourceRange; |
| import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; |
| import org.eclipse.jdt.core.formatter.IndentManipulation; |
| import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
| import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner; |
| import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData; |
| 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.dom.rewrite.ASTRewriteFormatter.BlockContext; |
| import org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteFormatter.NodeMarker; |
| import org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteFormatter.Prefix; |
| import org.eclipse.jdt.internal.core.dom.rewrite.NodeInfoStore.CopyPlaceholderData; |
| import org.eclipse.jdt.internal.core.dom.rewrite.NodeInfoStore.StringPlaceholderData; |
| import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore.CopySourceInfo; |
| import org.eclipse.text.edits.CopySourceEdit; |
| import org.eclipse.text.edits.CopyTargetEdit; |
| import org.eclipse.text.edits.DeleteEdit; |
| import org.eclipse.text.edits.InsertEdit; |
| import org.eclipse.text.edits.MoveSourceEdit; |
| import org.eclipse.text.edits.MoveTargetEdit; |
| import org.eclipse.text.edits.RangeMarker; |
| import org.eclipse.text.edits.ReplaceEdit; |
| import org.eclipse.text.edits.TextEdit; |
| import org.eclipse.text.edits.TextEditGroup; |
| |
| |
| /** |
| * Infrastructure to support code modifications. Existing code must stay untouched, new code |
| * added with correct formatting, moved code left with the user's formatting / comments. |
| * Idea: |
| * - Get the AST for existing code |
| * - Describe changes |
| * - This visitor analyzes the changes or annotations and generates text edits |
| * (text manipulation API) that describe the required code changes. |
| */ |
| @SuppressWarnings({ "rawtypes", "unchecked" }) |
| public final class ASTRewriteAnalyzer extends ASTVisitor { |
| |
| /** @deprecated using deprecated code */ |
| private static final ChildPropertyDescriptor INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY = ArrayType.COMPONENT_TYPE_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final SimplePropertyDescriptor INTERNAL_FIELD_MODIFIERS_PROPERTY = FieldDeclaration.MODIFIERS_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final SimplePropertyDescriptor INTERNAL_INITIALIZER_MODIFIERS_PROPERTY3 = Initializer.MODIFIERS_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final SimplePropertyDescriptor INTERNAL_METHOD_MODIFIERS_PROPERTY2 = MethodDeclaration.MODIFIERS_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final ChildPropertyDescriptor INTERNAL_METHOD_RETURN_TYPE_PROPERTY = MethodDeclaration.RETURN_TYPE_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final SimplePropertyDescriptor INTERNAL_METHOD_EXTRA_DIMENSIONS_PROPERTY = MethodDeclaration.EXTRA_DIMENSIONS_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final ChildListPropertyDescriptor INTERNAL_METHOD_THROWN_EXCEPTIONS_PROPERTY = MethodDeclaration.THROWN_EXCEPTIONS_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final SimplePropertyDescriptor INTERNAL_TYPE_MODIFIERS_PROPERTY = TypeDeclaration.MODIFIERS_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final ChildPropertyDescriptor INTERNAL_TYPE_SUPERCLASS_PROPERTY = TypeDeclaration.SUPERCLASS_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final ChildListPropertyDescriptor INTERNAL_TYPE_SUPER_INTERFACES_PROPERTY = TypeDeclaration.SUPER_INTERFACES_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final ChildPropertyDescriptor INTERNAL_CIC_NAME_PROPERTY = ClassInstanceCreation.NAME_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final SimplePropertyDescriptor INTERNAL_FRAGMENT_EXTRA_DIMENSIONS_PROPERTY = VariableDeclarationFragment.EXTRA_DIMENSIONS_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final ChildPropertyDescriptor INTERNAL_TDS_TYPE_DECLARATION_PROPERTY = TypeDeclarationStatement.TYPE_DECLARATION_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final SimplePropertyDescriptor INTERNAL_VARIABLE_MODIFIERS_PROPERTY = SingleVariableDeclaration.MODIFIERS_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final SimplePropertyDescriptor INTERNAL_VARIABLE_EXTRA_DIMENSIONS_PROPERTY = SingleVariableDeclaration.EXTRA_DIMENSIONS_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final SimplePropertyDescriptor INTERNAL_VDE_MODIFIERS_PROPERTY = VariableDeclarationExpression.MODIFIERS_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final SimplePropertyDescriptor INTERNAL_VDS_MODIFIERS_PROPERTY = VariableDeclarationStatement.MODIFIERS_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final ChildListPropertyDescriptor INTERNAL_TRY_STATEMENT_RESOURCES_PROPERTY = TryStatement.RESOURCES_PROPERTY; |
| |
| /** @deprecated using deprecated code */ |
| private static final int JLS2_INTERNAL = AST.JLS2; |
| |
| /** @deprecated using deprecated code */ |
| private static final int JLS3_INTERNAL = AST.JLS3; |
| |
| /** @deprecated using deprecated code */ |
| private static final int JLS4_INTERNAL = AST.JLS4; |
| |
| /** @deprecated using deprecated code */ |
| private static final int JLS8_INTERNAL = AST.JLS8; |
| |
| /** @deprecated using deprecated code */ |
| private static final int JLS9_INTERNAL = AST.JLS9; |
| |
| |
| TextEdit currentEdit; |
| final RewriteEventStore eventStore; // used from inner classes |
| |
| private TokenScanner tokenScanner; // shared scanner |
| |
| private final Map sourceCopyInfoToEdit; |
| private final Stack sourceCopyEndNodes; |
| |
| private final char[] content; |
| private final LineInformation lineInfo; |
| private final ASTRewriteFormatter formatter; |
| private final NodeInfoStore nodeInfos; |
| private final TargetSourceRangeComputer extendedSourceRangeComputer; |
| private final LineCommentEndOffsets lineCommentEndOffsets; |
| |
| private int beforeRequiredSpaceIndex = -1; |
| |
| Map options; |
| |
| private RecoveryScannerData recoveryScannerData; |
| |
| /** |
| * Constructor for ASTRewriteAnalyzer. |
| * <p>The given options cannot be null.</p> |
| * |
| * @param content the content of the compilation unit to rewrite. |
| * @param lineInfo line information for the content of the compilation unit to rewrite. |
| * @param rootEdit the edit to add all generated edits to |
| * @param eventStore the event store containing the description of changes |
| * @param nodeInfos annotations to nodes, such as if a node is a string placeholder or a copy target |
| * @param comments list of comments of the compilation unit to rewrite (elements of type <code>Comment</code>) or <code>null</code>. |
| * @param options the current jdt.core options (formatting/compliance) |
| * @param extendedSourceRangeComputer the source range computer to use |
| * @param recoveryScannerData internal data used by {@link RecoveryScanner} |
| */ |
| public ASTRewriteAnalyzer( |
| char[] content, |
| LineInformation lineInfo, |
| String lineDelim, |
| TextEdit rootEdit, |
| RewriteEventStore eventStore, |
| NodeInfoStore nodeInfos, |
| List comments, |
| Map options, |
| TargetSourceRangeComputer extendedSourceRangeComputer, |
| RecoveryScannerData recoveryScannerData) { |
| this.eventStore= eventStore; |
| this.content= content; |
| this.lineInfo= lineInfo; |
| this.nodeInfos= nodeInfos; |
| this.tokenScanner= null; |
| this.currentEdit= rootEdit; |
| this.sourceCopyInfoToEdit= new IdentityHashMap(); |
| this.sourceCopyEndNodes= new Stack(); |
| |
| this.formatter= new ASTRewriteFormatter(nodeInfos, eventStore, options, lineDelim); |
| |
| this.extendedSourceRangeComputer = extendedSourceRangeComputer; |
| this.lineCommentEndOffsets= new LineCommentEndOffsets(comments); |
| |
| this.options = options; |
| |
| this.recoveryScannerData = recoveryScannerData; |
| } |
| |
| final TokenScanner getScanner() { |
| if (this.tokenScanner == null) { |
| CompilerOptions compilerOptions = new CompilerOptions(this.options); |
| Scanner scanner; |
| if (this.recoveryScannerData == null) { |
| scanner = |
| new Scanner( |
| true,/*tokenizeComments*/ |
| false,/*tokenizeWhiteSpace*/ |
| false,/*checkNonExternalizedStringLiterals*/ |
| compilerOptions.sourceLevel, |
| compilerOptions.complianceLevel, |
| null/*taskTags*/, |
| null/*taskPriorities*/, |
| true/*taskCaseSensitive*/); |
| } else { |
| scanner = |
| new RecoveryScanner( |
| false,/*tokenizeWhiteSpace*/ |
| false,/*checkNonExternalizedStringLiterals*/ |
| compilerOptions.sourceLevel, |
| compilerOptions.complianceLevel, |
| null/*taskTags*/, |
| null/*taskPriorities*/, |
| true/*taskCaseSensitive*/, |
| this.recoveryScannerData); |
| } |
| scanner.setSource(this.content); |
| this.tokenScanner= new TokenScanner(scanner); |
| } |
| return this.tokenScanner; |
| } |
| |
| final char[] getContent() { |
| return this.content; |
| } |
| |
| final LineInformation getLineInformation() { |
| return this.lineInfo; |
| } |
| |
| final LineCommentEndOffsets getLineCommentEndOffsets() { |
| return this.lineCommentEndOffsets; |
| } |
| /** |
| * Returns the extended source range for a node. |
| * |
| * @return an extended source range (never null) |
| * @since 3.1 |
| */ |
| final SourceRange getExtendedRange(ASTNode node) { |
| if (this.eventStore.isRangeCopyPlaceholder(node)) { |
| return new SourceRange(node.getStartPosition(), node.getLength()); |
| } |
| return this.extendedSourceRangeComputer.computeSourceRange(node); |
| } |
| |
| final int getExtendedOffset(ASTNode node) { |
| return getExtendedRange(node).getStartPosition(); |
| } |
| |
| final int getExtendedEnd(ASTNode node) { |
| TargetSourceRangeComputer.SourceRange range= getExtendedRange(node); |
| return range.getStartPosition() + range.getLength(); |
| } |
| |
| final TextEdit getCopySourceEdit(CopySourceInfo info) { |
| TextEdit edit= (TextEdit) this.sourceCopyInfoToEdit.get(info); |
| if (edit == null) { |
| SourceRange range= getExtendedRange(info.getNode()); |
| int start= range.getStartPosition(); |
| int end= start + range.getLength(); |
| if (info.isMove) { |
| MoveSourceEdit moveSourceEdit= new MoveSourceEdit(start, end - start); |
| moveSourceEdit.setTargetEdit(new MoveTargetEdit(0)); |
| edit= moveSourceEdit; |
| } else { |
| CopySourceEdit copySourceEdit= new CopySourceEdit(start, end - start); |
| copySourceEdit.setTargetEdit(new CopyTargetEdit(0)); |
| edit= copySourceEdit; |
| } |
| this.sourceCopyInfoToEdit.put(info, edit); |
| } |
| return edit; |
| } |
| |
| private final int getChangeKind(ASTNode node, StructuralPropertyDescriptor property) { |
| RewriteEvent event= getEvent(node, property); |
| if (event != null) { |
| return event.getChangeKind(); |
| } |
| return RewriteEvent.UNCHANGED; |
| } |
| |
| private final boolean hasChildrenChanges(ASTNode node) { |
| return this.eventStore.hasChangedProperties(node); |
| } |
| |
| private final boolean isChanged(ASTNode node, StructuralPropertyDescriptor property) { |
| RewriteEvent event= getEvent(node, property); |
| if (event != null) { |
| return event.getChangeKind() != RewriteEvent.UNCHANGED; |
| } |
| return false; |
| } |
| |
| private final boolean isCollapsed(ASTNode node) { |
| return this.nodeInfos.isCollapsed(node); |
| } |
| |
| final boolean isInsertBoundToPrevious(ASTNode node) { |
| return this.eventStore.isInsertBoundToPrevious(node); |
| } |
| |
| private final TextEditGroup getEditGroup(ASTNode parent, StructuralPropertyDescriptor property) { |
| RewriteEvent event= getEvent(parent, property); |
| if (event != null) { |
| return getEditGroup(event); |
| } |
| return null; |
| } |
| |
| final RewriteEvent getEvent(ASTNode parent, StructuralPropertyDescriptor property) { |
| return this.eventStore.getEvent(parent, property); |
| } |
| |
| final TextEditGroup getEditGroup(RewriteEvent change) { |
| return this.eventStore.getEventEditGroup(change); |
| } |
| |
| private final Object getOriginalValue(ASTNode parent, StructuralPropertyDescriptor property) { |
| return this.eventStore.getOriginalValue(parent, property); |
| } |
| |
| private final Object getNewValue(ASTNode parent, StructuralPropertyDescriptor property) { |
| return this.eventStore.getNewValue(parent, property); |
| } |
| |
| final void addEdit(TextEdit edit) { |
| this.currentEdit.addChild(edit); |
| } |
| |
| final String getLineDelimiter() { |
| return this.formatter.getLineDelimiter(); |
| } |
| |
| final String createIndentString(int indent) { |
| return this.formatter.createIndentString(indent); |
| } |
| |
| final private String getIndentOfLine(int pos) { |
| int line= getLineInformation().getLineOfOffset(pos); |
| if (line >= 0) { |
| char[] cont= getContent(); |
| int lineStart= getLineInformation().getLineOffset(line); |
| int i= lineStart; |
| while (i < cont.length && IndentManipulation.isIndentChar(this.content[i])) { |
| i++; |
| } |
| return new String(cont, lineStart, i - lineStart); |
| } |
| return Util.EMPTY_STRING; |
| } |
| |
| |
| final String getIndentAtOffset(int pos) { |
| return this.formatter.getIndentString(getIndentOfLine(pos)); |
| } |
| |
| final void doTextInsert(int offset, String insertString, TextEditGroup editGroup) { |
| if (insertString.length() > 0) { |
| // bug fix for 95839: problem with inserting at the end of a line comment |
| if (this.lineCommentEndOffsets.isEndOfLineComment(offset, this.content)) { |
| if (!insertString.startsWith(getLineDelimiter())) { |
| TextEdit edit= new InsertEdit(offset, getLineDelimiter()); // add a line delimiter |
| addEdit(edit); |
| if (editGroup != null) { |
| addEditGroup(editGroup, edit); |
| } |
| } |
| this.lineCommentEndOffsets.remove(offset); // only one line delimiter per line comment required |
| } |
| TextEdit edit= new InsertEdit(offset, insertString); |
| addEdit(edit); |
| if (editGroup != null) { |
| addEditGroup(editGroup, edit); |
| } |
| } |
| } |
| |
| final void addEditGroup(TextEditGroup editGroup, TextEdit edit) { |
| editGroup.addTextEdit(edit); |
| } |
| |
| final TextEdit doTextRemove(int offset, int len, TextEditGroup editGroup) { |
| if (len == 0) { |
| return null; |
| } |
| TextEdit edit= new DeleteEdit(offset, len); |
| addEdit(edit); |
| if (editGroup != null) { |
| addEditGroup(editGroup, edit); |
| } |
| return edit; |
| } |
| |
| final void doTextRemoveAndVisit(int offset, int len, ASTNode node, TextEditGroup editGroup) { |
| TextEdit edit= doTextRemove(offset, len, editGroup); |
| if (edit != null) { |
| this.currentEdit= edit; |
| voidVisit(node); |
| this.currentEdit= edit.getParent(); |
| } else { |
| voidVisit(node); |
| } |
| } |
| |
| final int doVisit(ASTNode node) { |
| node.accept(this); |
| return getExtendedEnd(node); |
| } |
| |
| private final int doVisit(ASTNode parent, StructuralPropertyDescriptor property, int offset) { |
| Object node= getOriginalValue(parent, property); |
| if (property.isChildProperty() && node != null) { |
| return doVisit((ASTNode) node); |
| } else if (property.isChildListProperty()) { |
| return doVisitList((List) node, offset); |
| } |
| return offset; |
| } |
| |
| private int doVisitList(List list, int offset) { |
| int endPos= offset; |
| for (Iterator iter= list.iterator(); iter.hasNext();) { |
| ASTNode curr= ((ASTNode) iter.next()); |
| endPos= doVisit(curr); |
| } |
| return endPos; |
| } |
| |
| final void voidVisit(ASTNode node) { |
| node.accept(this); |
| } |
| |
| private final void voidVisit(ASTNode parent, StructuralPropertyDescriptor property) { |
| Object node= getOriginalValue(parent, property); |
| if (property.isChildProperty() && node != null) { |
| voidVisit((ASTNode) node); |
| } else if (property.isChildListProperty()) { |
| voidVisitList((List) node); |
| } |
| } |
| |
| private void voidVisitList(List list) { |
| for (Iterator iter= list.iterator(); iter.hasNext();) { |
| doVisit(((ASTNode) iter.next())); |
| } |
| } |
| |
| private final boolean doVisitUnchangedChildren(ASTNode parent) { |
| List properties= parent.structuralPropertiesForType(); |
| for (int i= 0; i < properties.size(); i++) { |
| voidVisit(parent, (StructuralPropertyDescriptor) properties.get(i)); |
| } |
| return false; |
| } |
| |
| |
| private final void doTextReplace(int offset, int len, String insertString, TextEditGroup editGroup) { |
| if (len > 0 || insertString.length() > 0) { |
| TextEdit edit= new ReplaceEdit(offset, len, insertString); |
| addEdit(edit); |
| if (editGroup != null) { |
| addEditGroup(editGroup, edit); |
| } |
| } |
| } |
| |
| private final TextEdit doTextCopy(TextEdit sourceEdit, int destOffset, int sourceIndentLevel, String destIndentString, TextEditGroup editGroup) { |
| TextEdit targetEdit; |
| SourceModifier modifier= new SourceModifier(sourceIndentLevel, destIndentString, this.formatter.getTabWidth(), this.formatter.getIndentWidth()); |
| |
| if (sourceEdit instanceof MoveSourceEdit) { |
| MoveSourceEdit moveEdit= (MoveSourceEdit) sourceEdit; |
| moveEdit.setSourceModifier(modifier); |
| |
| targetEdit= new MoveTargetEdit(destOffset, moveEdit); |
| addEdit(targetEdit); |
| } else { |
| CopySourceEdit copyEdit= (CopySourceEdit) sourceEdit; |
| copyEdit.setSourceModifier(modifier); |
| |
| targetEdit= new CopyTargetEdit(destOffset, copyEdit); |
| addEdit(targetEdit); |
| } |
| |
| if (editGroup != null) { |
| addEditGroup(editGroup, sourceEdit); |
| addEditGroup(editGroup, targetEdit); |
| } |
| return targetEdit; |
| |
| } |
| |
| private void changeNotSupported(ASTNode node) { |
| Assert.isTrue(false, "Change not supported in " + node.getClass().getName()); //$NON-NLS-1$ |
| } |
| |
| |
| class ListRewriter { |
| protected String constantSeparator; |
| protected int startPos; |
| |
| protected RewriteEvent[] list; |
| |
| protected final ASTNode getOriginalNode(int index) { |
| return (ASTNode) this.list[index].getOriginalValue(); |
| } |
| |
| protected final ASTNode getNewNode(int index) { |
| return (ASTNode) this.list[index].getNewValue(); |
| } |
| |
| protected String getSeparatorString(int nodeIndex) { |
| return this.constantSeparator; |
| } |
| |
| protected int getInitialIndent() { |
| return getIndent(this.startPos); |
| } |
| |
| protected int getNodeIndent(int nodeIndex) { |
| ASTNode node= getOriginalNode(nodeIndex); |
| if (node == null) { |
| for (int i= nodeIndex - 1; i>= 0; i--) { |
| ASTNode curr= getOriginalNode(i); |
| if (curr != null) { |
| return getIndent(curr.getStartPosition()); |
| } |
| } |
| return getInitialIndent(); |
| } |
| return getIndent(node.getStartPosition()); |
| } |
| |
| protected int getStartOfNextNode(int nextIndex, int defaultPos) { |
| for (int i= nextIndex; i < this.list.length; i++) { |
| RewriteEvent elem= this.list[i]; |
| if (elem.getChangeKind() != RewriteEvent.INSERTED) { |
| ASTNode node= (ASTNode) elem.getOriginalValue(); |
| return getExtendedOffset(node); |
| } |
| } |
| return defaultPos; |
| } |
| |
| protected int getEndOfNode(ASTNode node) { |
| return getExtendedEnd(node); |
| } |
| |
| public final int rewriteList(ASTNode parent, StructuralPropertyDescriptor property, int offset, String keyword, String separator) { |
| this.constantSeparator= separator; |
| return rewriteList(parent, property, keyword, null, offset); |
| } |
| |
| private boolean insertAfterSeparator(ASTNode node) { |
| return !isInsertBoundToPrevious(node); |
| } |
| |
| private boolean lineCommentSwallowsActualCode(int prevEnd) { |
| if (ASTRewriteAnalyzer.this.getLineCommentEndOffsets().isEndOfLineComment(prevEnd)) { |
| int lastEndOffset = getEndOfNode((ASTNode) this.list[this.list.length - 1].getOriginalValue()); |
| LineInformation lInfo = ASTRewriteAnalyzer.this.getLineInformation(); |
| try { |
| return lInfo.getLineOfOffset(lastEndOffset) == lInfo.getLineOfOffset(getScanner().getNextStartOffset(lastEndOffset, false)); |
| } catch (CoreException e) { |
| // ignore |
| } |
| } |
| return false; |
| } |
| |
| protected boolean mustRemoveSeparator(int originalOffset, int nodeIndex) { |
| return true; |
| } |
| |
| private int rewriteList( |
| ASTNode parent, |
| StructuralPropertyDescriptor property, |
| String keyword, |
| String endKeyword, |
| int offset) { |
| this.startPos= offset; |
| this.list= getEvent(parent, property).getChildren(); |
| |
| int total= this.list.length; |
| if (total == 0) { |
| return this.startPos; |
| } |
| |
| int currPos= -1; |
| |
| int lastNonInsert= -1; |
| int lastNonDelete= -1; |
| |
| for (int i= 0; i < total; i++) { |
| int currMark= this.list[i].getChangeKind(); |
| |
| if (currMark != RewriteEvent.INSERTED) { |
| lastNonInsert= i; |
| if (currPos == -1) { |
| ASTNode elem= (ASTNode) this.list[i].getOriginalValue(); |
| currPos= getExtendedOffset(elem); |
| } |
| } |
| if (currMark != RewriteEvent.REMOVED) { |
| lastNonDelete= i; |
| } |
| } |
| |
| boolean insertNew = currPos == -1; |
| if (insertNew) { // only inserts |
| if (keyword.length() > 0) { // creating a new list -> insert keyword first (e.g. " throws ") |
| TextEditGroup editGroup= getEditGroup(this.list[0]); // first node is insert |
| doTextInsert(offset, keyword, editGroup); |
| } |
| currPos= offset; |
| } |
| if (lastNonDelete == -1) { // all removed, set back to start so the keyword is removed as well |
| currPos= offset; |
| } |
| |
| int prevEnd= currPos; |
| int prevMark= RewriteEvent.UNCHANGED; |
| |
| final int NONE= 0, NEW= 1, EXISTING= 2; |
| int separatorState= NEW; |
| |
| for (int i= 0; i < total; i++) { |
| RewriteEvent currEvent= this.list[i]; |
| int currMark= currEvent.getChangeKind(); |
| int nextIndex= i + 1; |
| |
| if (currMark == RewriteEvent.INSERTED) { |
| TextEditGroup editGroup= getEditGroup(currEvent); |
| ASTNode node= (ASTNode) currEvent.getNewValue(); |
| |
| if (separatorState == NONE) { // element after last existing element (but not first) |
| doTextInsert(currPos, getSeparatorString(i - 1), editGroup); // insert separator |
| separatorState= NEW; |
| } |
| if (separatorState == NEW || insertAfterSeparator(node)) { |
| if (separatorState == EXISTING) { |
| updateIndent(prevMark, currPos, i, editGroup); |
| } |
| |
| doTextInsert(currPos, node, getNodeIndent(i), true, editGroup); // insert node |
| |
| separatorState= NEW; |
| if (i != lastNonDelete) { |
| if (this.list[nextIndex].getChangeKind() != RewriteEvent.INSERTED) { |
| doTextInsert(currPos, getSeparatorString(i), editGroup); // insert separator |
| } else { |
| separatorState= NONE; |
| } |
| } |
| } else { // EXISTING && insert before separator |
| doTextInsert(prevEnd, getSeparatorString(i - 1), editGroup); |
| doTextInsert(prevEnd, node, getNodeIndent(i), true, editGroup); |
| } |
| if (insertNew) { |
| if (endKeyword != null && endKeyword.length() > 0) { |
| doTextInsert(currPos, endKeyword, editGroup); |
| } |
| } |
| } else if (currMark == RewriteEvent.REMOVED) { |
| ASTNode node= (ASTNode) currEvent.getOriginalValue(); |
| TextEditGroup editGroup= getEditGroup(currEvent); |
| int currEnd= getEndOfNode(node); |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=306524 |
| // Check for leading comments that are not part of extended range, and prevent them |
| // from getting removed. |
| try { |
| TokenScanner scanner = getScanner(); |
| int newOffset = prevEnd; |
| int extendedOffset = getExtendedOffset(node); |
| // Try to find the end of the last comment which is not part of extended source |
| // range of the node. |
| while (TokenScanner.isComment(scanner.readNext(newOffset, false))) { |
| int tempOffset = scanner.getNextEndOffset(newOffset, false); |
| // check whether the comment is part of extended source range of the node. |
| // If it is then we need to stop. |
| if (tempOffset < extendedOffset) { |
| newOffset = tempOffset; |
| } else { |
| break; |
| } |
| } |
| if (currPos < newOffset) { |
| currPos = extendedOffset; |
| } |
| prevEnd = newOffset; |
| } catch (CoreException e) { |
| // ignore |
| } |
| if (i > lastNonDelete && separatorState == EXISTING) { |
| // is last, remove previous separator: split delete to allow range copies |
| doTextRemove(prevEnd, currPos - prevEnd, editGroup); // remove separator |
| doTextRemoveAndVisit(currPos, currEnd - currPos, node, editGroup); // remove node |
| if (lineCommentSwallowsActualCode(prevEnd)) doTextInsert(currEnd, getLineDelimiter(), editGroup); |
| currPos= currEnd; |
| prevEnd= currEnd; |
| } else { |
| if (i < lastNonDelete) { |
| updateIndent(prevMark, currPos, i, editGroup); |
| } |
| |
| // remove element and next separator |
| int end= getStartOfNextNode(nextIndex, currEnd); // start of next |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=306524 |
| // Check for trailing comments that are not part of extended range, and prevent them |
| // from getting removed. |
| try { |
| TokenScanner scanner = getScanner(); |
| int nextToken= scanner.readNext(currEnd, false); |
| if (TokenScanner.isComment(nextToken)) { |
| // the separator also has comments that are not part of extended |
| // source range of this node or the next node. So dont remove the separator |
| if (end != scanner.getNextStartOffset(currEnd, false)) { |
| // If this condition were true, comments just found as part of the separator would've basically been |
| // part of the extended source range of the next node. So 'end' wud've safely been set to the correct position |
| // and no change is needed. |
| end = currEnd; |
| } |
| } |
| } catch (CoreException e) { |
| // ignore |
| } |
| doTextRemoveAndVisit(currPos, currEnd - currPos, node, getEditGroup(currEvent)); // remove node |
| if (mustRemoveSeparator(currPos, i)) { |
| doTextRemove(currEnd, end - currEnd, editGroup); // remove separator |
| } |
| currPos= end; |
| prevEnd= currEnd; |
| separatorState= NEW; |
| } |
| } else { // replaced or unchanged |
| if (currMark == RewriteEvent.REPLACED) { |
| ASTNode node= (ASTNode) currEvent.getOriginalValue(); |
| int currEnd= getEndOfNode(node); |
| |
| TextEditGroup editGroup= getEditGroup(currEvent); |
| ASTNode changed= (ASTNode) currEvent.getNewValue(); |
| |
| updateIndent(prevMark, currPos, i, editGroup); |
| // make sure that comments between last modified source position and extended starting position of |
| // node to be replaced are not touched |
| try { |
| TokenScanner scanner = getScanner(); |
| int newOffset = prevEnd; |
| int extendedOffset = getExtendedOffset(node); |
| // Try to find the end of the last comment which is not part of extended source |
| // range of the node. |
| while (TokenScanner.isComment(scanner.readNext(newOffset, false))) { |
| int tempOffset = scanner.getNextEndOffset(newOffset, false); |
| // check whether the comment is part of extended source range of the node. |
| // If it is then we need to stop. |
| if (tempOffset < extendedOffset) { |
| newOffset = tempOffset; |
| } else { |
| break; |
| } |
| } |
| if (currPos < newOffset) { |
| currPos = extendedOffset; |
| } |
| } catch (CoreException e) { |
| // ignore |
| } |
| doTextRemoveAndVisit(currPos, currEnd - currPos, node, editGroup); |
| doTextInsert(currPos, changed, getNodeIndent(i), true, editGroup); |
| |
| prevEnd= currEnd; |
| } else { // is unchanged |
| ASTNode node= (ASTNode) currEvent.getOriginalValue(); |
| voidVisit(node); |
| } |
| if (i == lastNonInsert) { // last node or next nodes are all inserts |
| separatorState= NONE; |
| if (currMark == RewriteEvent.UNCHANGED) { |
| ASTNode node= (ASTNode) currEvent.getOriginalValue(); |
| prevEnd= getEndOfNode(node); |
| } |
| currPos= prevEnd; |
| } else if (this.list[nextIndex].getChangeKind() != RewriteEvent.UNCHANGED) { |
| // no updates needed while nodes are unchanged |
| if (currMark == RewriteEvent.UNCHANGED) { |
| ASTNode node= (ASTNode) currEvent.getOriginalValue(); |
| prevEnd= getEndOfNode(node); |
| } |
| currPos= getStartOfNextNode(nextIndex, prevEnd); // start of next |
| separatorState= EXISTING; |
| } |
| } |
| |
| prevMark = currMark; |
| } |
| return currPos; |
| } |
| |
| public final int rewriteList(ASTNode parent, StructuralPropertyDescriptor property, int offset, String keyword) { |
| return rewriteList(parent, property, keyword, null, offset); |
| } |
| |
| protected void updateIndent(int prevMark, int originalOffset, int nodeIndex, TextEditGroup editGroup) { |
| // Do nothing. |
| } |
| |
| public final int rewriteList(ASTNode parent, StructuralPropertyDescriptor property, int offset, String keyword, String endKeyword, String separator) { |
| this.constantSeparator= separator; |
| return rewriteList(parent, property, keyword, endKeyword, offset); |
| } |
| } |
| |
| private int rewriteRequiredNode(ASTNode parent, StructuralPropertyDescriptor property) { |
| RewriteEvent event= getEvent(parent, property); |
| if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) { |
| ASTNode node= (ASTNode) event.getOriginalValue(); |
| TextEditGroup editGroup= getEditGroup(event); |
| SourceRange range= getExtendedRange(node); |
| int offset= range.getStartPosition(); |
| int length= range.getLength(); |
| doTextRemoveAndVisit(offset, length, node, editGroup); |
| doTextInsert(offset, (ASTNode) event.getNewValue(), getIndent(offset), true, editGroup); |
| return offset + length; |
| } |
| return doVisit(parent, property, 0); |
| } |
| |
| private int rewriteNode(ASTNode parent, StructuralPropertyDescriptor property, int offset, Prefix prefix) { |
| RewriteEvent event= getEvent(parent, property); |
| if (event != null) { |
| switch (event.getChangeKind()) { |
| case RewriteEvent.INSERTED: { |
| ASTNode node= (ASTNode) event.getNewValue(); |
| TextEditGroup editGroup= getEditGroup(event); |
| int indent= getIndent(offset); |
| doTextInsert(offset, prefix.getPrefix(indent), editGroup); |
| doTextInsert(offset, node, indent, true, editGroup); |
| return offset; |
| } |
| case RewriteEvent.REMOVED: { |
| ASTNode node= (ASTNode) event.getOriginalValue(); |
| TextEditGroup editGroup= getEditGroup(event); |
| |
| // if there is a prefix, remove the prefix as well |
| int nodeEnd; |
| int len; |
| if (offset == 0) { |
| SourceRange range= getExtendedRange(node); |
| offset= range.getStartPosition(); |
| len= range.getLength(); |
| nodeEnd= offset+len; |
| } else { |
| nodeEnd= getExtendedEnd(node); |
| len= nodeEnd-offset; |
| } |
| doTextRemoveAndVisit(offset, len, node, editGroup); |
| return nodeEnd; |
| } |
| case RewriteEvent.REPLACED: { |
| ASTNode node= (ASTNode) event.getOriginalValue(); |
| TextEditGroup editGroup= getEditGroup(event); |
| SourceRange range= getExtendedRange(node); |
| int nodeOffset= range.getStartPosition(); |
| int nodeLen= range.getLength(); |
| doTextRemoveAndVisit(nodeOffset, nodeLen, node, editGroup); |
| doTextInsert(nodeOffset, (ASTNode) event.getNewValue(), getIndent(offset), true, editGroup); |
| return nodeOffset + nodeLen; |
| } |
| } |
| } |
| return doVisit(parent, property, offset); |
| } |
| |
| private int rewriteJavadoc(ASTNode node, StructuralPropertyDescriptor property) { |
| int pos= rewriteNode(node, property, node.getStartPosition(), ASTRewriteFormatter.NONE); |
| int changeKind= getChangeKind(node, property); |
| if (changeKind == RewriteEvent.INSERTED) { |
| String indent= getLineDelimiter() + getIndentAtOffset(pos); |
| doTextInsert(pos, indent, getEditGroup(node, property)); |
| } else if (changeKind == RewriteEvent.REMOVED) { |
| try { |
| getScanner().readNext(pos, false); |
| doTextRemove(pos, getScanner().getCurrentStartOffset() - pos, getEditGroup(node, property)); |
| pos= getScanner().getCurrentStartOffset(); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| return pos; |
| } |
| |
| |
| /* |
| * endpos can be -1 -> use the end pos of the body |
| */ |
| private int rewriteBodyNode(ASTNode parent, StructuralPropertyDescriptor property, int offset, int endPos, int indent, BlockContext context) { |
| RewriteEvent event= getEvent(parent, property); |
| if (event != null) { |
| switch (event.getChangeKind()) { |
| case RewriteEvent.INSERTED: { |
| ASTNode node= (ASTNode) event.getNewValue(); |
| TextEditGroup editGroup= getEditGroup(event); |
| |
| String[] strings= context.getPrefixAndSuffix(indent, node, this.eventStore); |
| |
| doTextInsert(offset, strings[0], editGroup); |
| doTextInsert(offset, node, indent, true, editGroup); |
| doTextInsert(offset, strings[1], editGroup); |
| return offset; |
| } |
| case RewriteEvent.REMOVED: { |
| ASTNode node= (ASTNode) event.getOriginalValue(); |
| if (endPos == -1) { |
| endPos= getExtendedEnd(node); |
| } |
| |
| TextEditGroup editGroup= getEditGroup(event); |
| // if there is a prefix, remove the prefix as well |
| int len= endPos - offset; |
| doTextRemoveAndVisit(offset, len, node, editGroup); |
| return endPos; |
| } |
| case RewriteEvent.REPLACED: { |
| ASTNode node= (ASTNode) event.getOriginalValue(); |
| boolean insertNewLine = false; |
| if (endPos == -1) { |
| int previousEnd = node.getStartPosition() + node.getLength(); |
| endPos= getExtendedEnd(node); |
| if (endPos != previousEnd) { |
| // check if the end is a comment |
| int token = TokenScanner.END_OF_FILE; |
| try { |
| token = getScanner().readNext(previousEnd, false); |
| } catch(CoreException e) { |
| // ignore |
| } |
| if (token == TerminalTokens.TokenNameCOMMENT_LINE) { |
| insertNewLine = true; |
| } |
| } |
| } |
| TextEditGroup editGroup= getEditGroup(event); |
| int nodeLen= endPos - offset; |
| |
| ASTNode replacingNode= (ASTNode) event.getNewValue(); |
| String[] strings= context.getPrefixAndSuffix(indent, replacingNode, this.eventStore); |
| doTextRemoveAndVisit(offset, nodeLen, node, editGroup); |
| |
| String prefix= strings[0]; |
| String insertedPrefix = prefix; |
| if (insertNewLine) { |
| insertedPrefix = getLineDelimiter() + this.formatter.createIndentString(indent) + insertedPrefix.trim() + ' '; |
| } |
| doTextInsert(offset, insertedPrefix, editGroup); |
| int lineStart= getCurrentLineStart(prefix, prefix.length()); |
| if (lineStart != 0) { |
| // prefix contains a new line: update the indent to the one used in the prefix |
| indent= this.formatter.computeIndentUnits(prefix.substring(lineStart)); |
| } |
| doTextInsert(offset, replacingNode, indent, true, editGroup); |
| doTextInsert(offset, strings[1], editGroup); |
| return endPos; |
| } |
| } |
| } |
| int pos= doVisit(parent, property, offset); |
| if (endPos != -1) { |
| return endPos; |
| } |
| return pos; |
| } |
| private int rewriteOptionalQualifier(ASTNode parent, StructuralPropertyDescriptor property, int startPos) { |
| RewriteEvent event= getEvent(parent, property); |
| if (event != null) { |
| switch (event.getChangeKind()) { |
| case RewriteEvent.INSERTED: { |
| ASTNode node= (ASTNode) event.getNewValue(); |
| TextEditGroup editGroup= getEditGroup(event); |
| doTextInsert(startPos, node, getIndent(startPos), true, editGroup); |
| doTextInsert(startPos, ".", editGroup); //$NON-NLS-1$ |
| return startPos; |
| } |
| case RewriteEvent.REMOVED: { |
| try { |
| ASTNode node= (ASTNode) event.getOriginalValue(); |
| TextEditGroup editGroup= getEditGroup(event); |
| int dotEnd= getScanner().getTokenEndOffset(TerminalTokens.TokenNameDOT, node.getStartPosition() + node.getLength()); |
| doTextRemoveAndVisit(startPos, dotEnd - startPos, node, editGroup); |
| return dotEnd; |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| break; |
| } |
| case RewriteEvent.REPLACED: { |
| ASTNode node= (ASTNode) event.getOriginalValue(); |
| TextEditGroup editGroup= getEditGroup(event); |
| SourceRange range= getExtendedRange(node); |
| int offset= range.getStartPosition(); |
| int length= range.getLength(); |
| |
| doTextRemoveAndVisit(offset, length, node, editGroup); |
| doTextInsert(offset, (ASTNode) event.getNewValue(), getIndent(startPos), true, editGroup); |
| try { |
| return getScanner().getTokenEndOffset(TerminalTokens.TokenNameDOT, offset + length); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| break; |
| } |
| } |
| } |
| Object node= getOriginalValue(parent, property); |
| if (node == null) { |
| return startPos; |
| } |
| int pos= doVisit((ASTNode) node); |
| try { |
| return getScanner().getTokenEndOffset(TerminalTokens.TokenNameDOT, pos); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return pos; |
| } |
| |
| class ParagraphListRewriter extends ListRewriter { |
| |
| public final static int DEFAULT_SPACING= 1; |
| |
| private int initialIndent; |
| private int separatorLines; |
| |
| public ParagraphListRewriter(int initialIndent, int separator) { |
| this.initialIndent= initialIndent; |
| this.separatorLines= separator; |
| } |
| |
| @Override |
| protected int getInitialIndent() { |
| return this.initialIndent; |
| } |
| |
| @Override |
| protected String getSeparatorString(int nodeIndex) { |
| return getSeparatorString(nodeIndex, nodeIndex + 1); |
| } |
| |
| protected String getSeparatorString(int nodeIndex, int nextNodeIndex) { |
| int newLines= this.separatorLines == -1 ? getNewLines(nodeIndex) : this.separatorLines; |
| |
| String lineDelim= getLineDelimiter(); |
| StringBuffer buf= new StringBuffer(lineDelim); |
| for (int i= 0; i < newLines; i++) { |
| buf.append(lineDelim); |
| } |
| buf.append(createIndentString(getNodeIndent(nextNodeIndex))); |
| return buf.toString(); |
| } |
| |
| private ASTNode getNode(int nodeIndex) { |
| ASTNode elem= (ASTNode) this.list[nodeIndex].getOriginalValue(); |
| if (elem == null) { |
| elem= (ASTNode) this.list[nodeIndex].getNewValue(); |
| } |
| return elem; |
| } |
| |
| private int getNewLines(int nodeIndex) { |
| ASTNode curr= getNode(nodeIndex); |
| ASTNode next= getNode(nodeIndex + 1); |
| |
| int currKind= curr.getNodeType(); |
| int nextKind= next.getNodeType(); |
| |
| ASTNode last= null; |
| ASTNode secondLast= null; |
| for (int i= 0; i < this.list.length; i++) { |
| ASTNode elem= (ASTNode) this.list[i].getOriginalValue(); |
| if (elem != null) { |
| if (last != null) { |
| if (elem.getNodeType() == nextKind && last.getNodeType() == currKind) { |
| return countEmptyLines(last); |
| } |
| secondLast= last; |
| } |
| last= elem; |
| } |
| } |
| if (currKind == ASTNode.FIELD_DECLARATION && nextKind == ASTNode.FIELD_DECLARATION ) { |
| return 0; |
| } |
| if (secondLast != null) { |
| return countEmptyLines(secondLast); |
| } |
| return DEFAULT_SPACING; |
| } |
| |
| private int countEmptyLines(ASTNode last) { |
| LineInformation lineInformation= getLineInformation(); |
| int lastLine= lineInformation.getLineOfOffset(getExtendedEnd(last)); |
| if (lastLine >= 0) { |
| int startLine= lastLine + 1; |
| int start= lineInformation.getLineOffset(startLine); |
| if (start < 0) { |
| return 0; |
| } |
| char[] cont= getContent(); |
| int i= start; |
| while (i < cont.length && ScannerHelper.isWhitespace(cont[i])) { |
| i++; |
| } |
| if (i > start) { |
| lastLine= lineInformation.getLineOfOffset(i); |
| if (lastLine > startLine) { |
| return lastLine - startLine; |
| } |
| } |
| } |
| return 0; |
| } |
| |
| @Override |
| protected boolean mustRemoveSeparator(int originalOffset, int nodeIndex) { |
| // Do not remove separator if the previous non removed node is on the same line and the next node is on another line |
| int previousNonRemovedNodeIndex = nodeIndex - 1; |
| while (previousNonRemovedNodeIndex >= 0 && this.list[previousNonRemovedNodeIndex].getChangeKind() == RewriteEvent.REMOVED) { |
| previousNonRemovedNodeIndex--; |
| } |
| |
| if (previousNonRemovedNodeIndex > -1) { |
| LineInformation lineInformation = getLineInformation(); |
| |
| RewriteEvent prevEvent = this.list[previousNonRemovedNodeIndex]; |
| int prevKind = prevEvent.getChangeKind(); |
| if (prevKind == RewriteEvent.UNCHANGED || prevKind == RewriteEvent.REPLACED) { |
| ASTNode prevNode = (ASTNode) this.list[previousNonRemovedNodeIndex].getOriginalValue(); |
| int prevEndPosition = prevNode.getStartPosition() + prevNode.getLength(); |
| int prevLine = lineInformation.getLineOfOffset(prevEndPosition); |
| int line = lineInformation.getLineOfOffset(originalOffset); |
| |
| if (prevLine == line && nodeIndex + 1 < this.list.length) { |
| RewriteEvent nextEvent = this.list[nodeIndex + 1]; |
| int nextKind = nextEvent.getChangeKind(); |
| |
| if (nextKind == RewriteEvent.UNCHANGED || prevKind == RewriteEvent.REPLACED) { |
| ASTNode nextNode = (ASTNode) nextEvent.getOriginalValue(); |
| int nextStartPosition = nextNode.getStartPosition(); |
| int nextLine = lineInformation.getLineOfOffset(nextStartPosition); |
| |
| return nextLine == line; |
| } |
| return false; |
| } |
| } |
| } |
| |
| return true; |
| } |
| } |
| |
| private int rewriteParagraphList(ASTNode parent, StructuralPropertyDescriptor property, int insertPos, int insertIndent, int separator, int lead) { |
| RewriteEvent event= getEvent(parent, property); |
| if (event == null || event.getChangeKind() == RewriteEvent.UNCHANGED) { |
| return doVisit(parent, property, insertPos); |
| } |
| |
| RewriteEvent[] events= event.getChildren(); |
| ParagraphListRewriter listRewriter= new ParagraphListRewriter(insertIndent, separator); |
| StringBuffer leadString= new StringBuffer(); |
| if (isAllOfKind(events, RewriteEvent.INSERTED)) { |
| for (int i= 0; i < lead; i++) { |
| leadString.append(getLineDelimiter()); |
| } |
| leadString.append(createIndentString(insertIndent)); |
| } |
| return listRewriter.rewriteList(parent, property, insertPos, leadString.toString()); |
| } |
| |
| private int rewriteOptionalTypeParameters(ASTNode parent, StructuralPropertyDescriptor property, int offset, String keyword, boolean adjustOnNext, boolean needsSpaceOnRemoveAll) { |
| int pos= offset; |
| RewriteEvent event= getEvent(parent, property); |
| if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { |
| RewriteEvent[] children= event.getChildren(); |
| try { |
| boolean isAllInserted= isAllOfKind(children, RewriteEvent.INSERTED); |
| if (isAllInserted && adjustOnNext) { |
| pos= getScanner().getNextStartOffset(pos, false); // adjust on next element |
| } |
| boolean isAllRemoved= !isAllInserted && isAllOfKind(children, RewriteEvent.REMOVED); |
| if (isAllRemoved) { // all removed: set start to left bracket |
| int posBeforeOpenBracket= getScanner().getTokenStartOffset(TerminalTokens.TokenNameLESS, pos); |
| if (posBeforeOpenBracket != pos) { |
| needsSpaceOnRemoveAll= false; |
| } |
| pos= posBeforeOpenBracket; |
| } |
| pos= new ListRewriter().rewriteList(parent, property, pos, String.valueOf('<'), ", "); //$NON-NLS-1$ |
| if (isAllRemoved) { // all removed: remove right and space up to next element |
| int endPos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameGREATER, pos); // set pos to '>' |
| endPos= getScanner().getNextStartOffset(endPos, false); |
| String replacement= needsSpaceOnRemoveAll ? String.valueOf(' ') : Util.EMPTY_STRING; |
| doTextReplace(pos, endPos - pos, replacement, getEditGroup(children[children.length - 1])); |
| return endPos; |
| } else if (isAllInserted) { |
| doTextInsert(pos, String.valueOf('>' + keyword), getEditGroup(children[children.length - 1])); |
| return pos; |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| pos= doVisit(parent, property, pos); |
| } |
| if (pos != offset) { // list contained some type -> parse after closing bracket |
| try { |
| return getScanner().getTokenEndOffset(TerminalTokens.TokenNameGREATER, pos); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| return pos; |
| } |
| |
| private boolean isAllOfKind(RewriteEvent[] children, int kind) { |
| for (int i= 0; i < children.length; i++) { |
| if (children[i].getChangeKind() != kind) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private int rewriteNodeList(ASTNode parent, StructuralPropertyDescriptor property, int pos, String keyword, String endKeyword, String separator) { |
| RewriteEvent event= getEvent(parent, property); |
| if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { |
| return new ListRewriter().rewriteList(parent, property, pos, keyword, endKeyword, separator); |
| } |
| return doVisit(parent, property, pos); |
| } |
| |
| private int rewriteNodeList(ASTNode parent, StructuralPropertyDescriptor property, int pos, String keyword, String separator) { |
| RewriteEvent event= getEvent(parent, property); |
| if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { |
| return new ListRewriter().rewriteList(parent, property, pos, keyword, separator); |
| } |
| return doVisit(parent, property, pos); |
| } |
| |
| private void rewriteMethodBody(MethodDeclaration parent, int startPos) { |
| RewriteEvent event= getEvent(parent, MethodDeclaration.BODY_PROPERTY); |
| if (event != null) { |
| switch (event.getChangeKind()) { |
| case RewriteEvent.INSERTED: { |
| int endPos= parent.getStartPosition() + parent.getLength(); |
| TextEditGroup editGroup= getEditGroup(event); |
| ASTNode body= (ASTNode) event.getNewValue(); |
| doTextRemove(startPos, endPos - startPos, editGroup); |
| int indent= getIndent(parent.getStartPosition()); |
| String prefix= this.formatter.METHOD_BODY.getPrefix(indent); |
| doTextInsert(startPos, prefix, editGroup); |
| doTextInsert(startPos, body, indent, true, editGroup); |
| return; |
| } |
| case RewriteEvent.REMOVED: { |
| TextEditGroup editGroup= getEditGroup(event); |
| ASTNode body= (ASTNode) event.getOriginalValue(); |
| int endPos= parent.getStartPosition() + parent.getLength(); |
| doTextRemoveAndVisit(startPos, endPos - startPos, body, editGroup); |
| doTextInsert(startPos, ";", editGroup); //$NON-NLS-1$ |
| return; |
| } |
| case RewriteEvent.REPLACED: { |
| TextEditGroup editGroup= getEditGroup(event); |
| ASTNode body= (ASTNode) event.getOriginalValue(); |
| doTextRemoveAndVisit(body.getStartPosition(), body.getLength(), body, editGroup); |
| doTextInsert(body.getStartPosition(), (ASTNode) event.getNewValue(), getIndent(body.getStartPosition()), true, editGroup); |
| return; |
| } |
| } |
| } |
| voidVisit(parent, MethodDeclaration.BODY_PROPERTY); |
| } |
| |
| protected int rewriteExtraDimensionsInfo(ASTNode node, int pos, ChildListPropertyDescriptor property) { |
| return rewriteNodeList(node, property, pos, " ", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| private int rewriteExtraDimensions(ASTNode parent, StructuralPropertyDescriptor property, int pos) { |
| RewriteEvent event= getEvent(parent, property); |
| if (event == null || event.getChangeKind() == RewriteEvent.UNCHANGED) { |
| return ((Integer) getOriginalValue(parent, property)).intValue(); |
| } |
| int oldDim= ((Integer) event.getOriginalValue()).intValue(); |
| int newDim= ((Integer) event.getNewValue()).intValue(); |
| |
| if (oldDim != newDim) { |
| TextEditGroup editGroup= getEditGroup(event); |
| rewriteExtraDimensions(oldDim, newDim, pos, editGroup); |
| } |
| return oldDim; |
| } |
| |
| private void rewriteExtraDimensions(int oldDim, int newDim, int pos, TextEditGroup editGroup) { |
| |
| if (oldDim < newDim) { |
| for (int i= oldDim; i < newDim; i++) { |
| doTextInsert(pos, "[]", editGroup); //$NON-NLS-1$ |
| } |
| } else if (newDim < oldDim) { |
| try { |
| getScanner().setOffset(pos); |
| for (int i= newDim; i < oldDim; i++) { |
| getScanner().readToToken(TerminalTokens.TokenNameRBRACKET); |
| } |
| doTextRemove(pos, getScanner().getCurrentEndOffset() - pos, editGroup); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| } |
| |
| private int getPosAfterToken(int pos, int token) { |
| try { |
| int nextToken= getScanner().readNext(pos, true); |
| if (nextToken == token) { |
| return getScanner().getCurrentEndOffset(); |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return pos; |
| } |
| /* |
| * Next token is a left brace. Returns the offset after the brace. For incomplete code, return the start offset. |
| */ |
| private int getPosAfterLeftBrace(int pos) { |
| try { |
| return getPosAfterToken(pos, TerminalTokens.TokenNameLBRACE); |
| } catch (IllegalArgumentException e) { |
| return pos; |
| } |
| } |
| |
| /* |
| * Next token is try keyword. Returns the offset after 'try' keyword. For incomplete code, return the start offset. |
| */ |
| private int getPosAfterTry(int pos) { |
| try { |
| int nextToken= getScanner().readNext(pos, true); |
| if (nextToken == TerminalTokens.TokenNametry) { |
| return getScanner().getCurrentEndOffset(); |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return pos; |
| } |
| |
| final int getIndent(int offset) { |
| return this.formatter.computeIndentUnits(getIndentOfLine(offset)); |
| } |
| |
| final void doTextInsert(int insertOffset, ASTNode node, int initialIndentLevel, boolean removeLeadingIndent, TextEditGroup editGroup) { |
| ArrayList markers= new ArrayList(); |
| String formatted= this.formatter.getFormattedResult(node, initialIndentLevel, markers); |
| |
| |
| int currPos= 0; |
| if (removeLeadingIndent) { |
| while (currPos < formatted.length() && ScannerHelper.isWhitespace(formatted.charAt(currPos))) { |
| currPos++; |
| } |
| } |
| for (int i= 0; i < markers.size(); i++) { // markers.size can change! |
| NodeMarker curr= (NodeMarker) markers.get(i); |
| |
| int offset= curr.offset; |
| if (offset >= currPos) { |
| String insertStr= formatted.substring(currPos, offset); |
| doTextInsert(insertOffset, insertStr, editGroup); // insert until the marker's begin |
| } else { |
| // already processed |
| continue; |
| } |
| |
| Object data= curr.data; |
| if (data instanceof TextEditGroup) { // tracking a node |
| // need to split and create 2 edits as tracking node can surround replaced node. |
| TextEdit edit= new RangeMarker(insertOffset, 0); |
| addEditGroup((TextEditGroup) data, edit); |
| addEdit(edit); |
| if (curr.length != 0) { |
| int end= offset + curr.length; |
| int k= i + 1; |
| while (k < markers.size() && ((NodeMarker) markers.get(k)).offset < end) { |
| k++; |
| } |
| curr.offset= end; |
| curr.length= 0; |
| markers.add(k, curr); // add again for end position |
| } |
| currPos= offset; |
| } else { |
| // If in the first line, there are cases (eg: catch clause) where the line will not be prefixed with |
| // proper indentation - see https://bugs.eclipse.org/bugs/show_bug.cgi?id=350285 |
| int lineOffset = getCurrentLineStart(formatted, offset); |
| String destIndentString = (lineOffset == 0) |
| ? this.formatter.createIndentString(initialIndentLevel) |
| : this.formatter.getIndentString(formatted.substring(lineOffset, offset)); |
| if (data instanceof CopyPlaceholderData) { // replace with a copy/move target |
| CopySourceInfo copySource= ((CopyPlaceholderData) data).copySource; |
| int srcIndentLevel= getIndent(copySource.getNode().getStartPosition()); |
| TextEdit sourceEdit= getCopySourceEdit(copySource); |
| doTextCopy(sourceEdit, insertOffset, srcIndentLevel, destIndentString, editGroup); |
| currPos= offset + curr.length; // continue to insert after the replaced string |
| if (needsNewLineForLineComment(copySource.getNode(), formatted, currPos)) { |
| doTextInsert(insertOffset, getLineDelimiter(), editGroup); |
| } |
| } else if (data instanceof StringPlaceholderData) { // replace with a placeholder |
| String code= ((StringPlaceholderData) data).code; |
| String str= this.formatter.changeIndent(code, 0, destIndentString); |
| doTextInsert(insertOffset, str, editGroup); |
| currPos= offset + curr.length; // continue to insert after the replaced string |
| } |
| } |
| |
| } |
| if (currPos < formatted.length()) { |
| String insertStr= formatted.substring(currPos); |
| doTextInsert(insertOffset, insertStr, editGroup); |
| } |
| } |
| |
| private boolean needsNewLineForLineComment(ASTNode node, String formatted, int offset) { |
| if (!this.lineCommentEndOffsets.isEndOfLineComment(getExtendedEnd(node), this.content)) { |
| return false; |
| } |
| // copied code ends with a line comment, but doesn't contain the new line |
| return offset < formatted.length() && !IndentManipulation.isLineDelimiterChar(formatted.charAt(offset)); |
| } |
| |
| private int getCurrentLineStart(String str, int pos) { |
| for (int i= pos - 1; i>= 0; i--) { |
| char ch= str.charAt(i); |
| if (IndentManipulation.isLineDelimiterChar(ch)) { |
| return i+1; |
| } |
| } |
| return 0; |
| } |
| |
| private void rewriteModifiers(ASTNode parent, StructuralPropertyDescriptor property, int offset) { |
| RewriteEvent event= getEvent(parent, property); |
| if (event == null || event.getChangeKind() != RewriteEvent.REPLACED) { |
| return; |
| } |
| try { |
| int oldModifiers= ((Integer) event.getOriginalValue()).intValue(); |
| int newModifiers= ((Integer) event.getNewValue()).intValue(); |
| TextEditGroup editGroup= getEditGroup(event); |
| |
| TokenScanner scanner= getScanner(); |
| |
| int tok= scanner.readNext(offset, false); |
| int startPos= scanner.getCurrentStartOffset(); |
| int nextStart= startPos; |
| loop: while (true) { |
| if (TokenScanner.isComment(tok)) { |
| tok= scanner.readNext(true); // next non-comment token |
| } |
| boolean keep= true; |
| switch (tok) { |
| case TerminalTokens.TokenNamepublic: keep= Modifier.isPublic(newModifiers); break; |
| case TerminalTokens.TokenNameprotected: keep= Modifier.isProtected(newModifiers); break; |
| case TerminalTokens.TokenNameprivate: keep= Modifier.isPrivate(newModifiers); break; |
| case TerminalTokens.TokenNamestatic: keep= Modifier.isStatic(newModifiers); break; |
| case TerminalTokens.TokenNamefinal: keep= Modifier.isFinal(newModifiers); break; |
| case TerminalTokens.TokenNameabstract: keep= Modifier.isAbstract(newModifiers); break; |
| case TerminalTokens.TokenNamenative: keep= Modifier.isNative(newModifiers); break; |
| case TerminalTokens.TokenNamevolatile: keep= Modifier.isVolatile(newModifiers); break; |
| case TerminalTokens.TokenNamestrictfp: keep= Modifier.isStrictfp(newModifiers); break; |
| case TerminalTokens.TokenNametransient: keep= Modifier.isTransient(newModifiers); break; |
| case TerminalTokens.TokenNamesynchronized: keep= Modifier.isSynchronized(newModifiers); break; |
| default: |
| break loop; |
| } |
| tok= getScanner().readNext(false); // include comments |
| int currPos= nextStart; |
| nextStart= getScanner().getCurrentStartOffset(); |
| if (!keep) { |
| doTextRemove(currPos, nextStart - currPos, editGroup); |
| } |
| } |
| int addedModifiers= newModifiers & ~oldModifiers; |
| if (addedModifiers != 0) { |
| if (startPos != nextStart) { |
| int visibilityModifiers= addedModifiers & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED); |
| if (visibilityModifiers != 0) { |
| StringBuffer buf= new StringBuffer(); |
| ASTRewriteFlattener.printModifiers(visibilityModifiers, buf); |
| doTextInsert(startPos, buf.toString(), editGroup); |
| addedModifiers &= ~visibilityModifiers; |
| } |
| } |
| StringBuffer buf= new StringBuffer(); |
| ASTRewriteFlattener.printModifiers(addedModifiers, buf); |
| doTextInsert(nextStart, buf.toString(), editGroup); |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| |
| class ModifierRewriter extends ListRewriter { |
| |
| private final Prefix annotationSeparation; |
| |
| public ModifierRewriter(Prefix annotationSeparation) { |
| this.annotationSeparation= annotationSeparation; |
| } |
| |
| @Override |
| protected String getSeparatorString(int nodeIndex) { |
| ASTNode curr= getNewNode(nodeIndex); |
| if (curr instanceof Annotation) { |
| return this.annotationSeparation.getPrefix(getNodeIndent(nodeIndex + 1)); |
| } |
| return super.getSeparatorString(nodeIndex); |
| } |
| } |
| |
| |
| private int rewriteModifiers2(ASTNode node, ChildListPropertyDescriptor property, int pos) { |
| RewriteEvent event= getEvent(node, property); |
| if (event == null || event.getChangeKind() == RewriteEvent.UNCHANGED) { |
| return doVisit(node, property, pos); |
| } |
| RewriteEvent[] children= event.getChildren(); |
| boolean isAllInsert= isAllOfKind(children, RewriteEvent.INSERTED); |
| boolean isAllRemove= isAllOfKind(children, RewriteEvent.REMOVED); |
| String keyword= Util.EMPTY_STRING; |
| boolean isVarargsAnnotationsProperty = property == SingleVariableDeclaration.VARARGS_ANNOTATIONS_PROPERTY; |
| if (isVarargsAnnotationsProperty) { |
| keyword= " "; //$NON-NLS-1$ |
| } else if (isAllInsert || isAllRemove) { |
| // update pos |
| try { |
| pos= getScanner().getNextStartOffset(pos, false); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| |
| boolean isAnnotationsProperty = isVarargsAnnotationsProperty |
| || node instanceof AnnotatableType && property == ((AnnotatableType) node).getAnnotationsProperty(); |
| Prefix formatterPrefix; |
| if (property == SingleVariableDeclaration.MODIFIERS2_PROPERTY || |
| property == VariableDeclarationExpression.MODIFIERS2_PROPERTY || |
| property == VariableDeclarationStatement.MODIFIERS2_PROPERTY || |
| property == TypeParameter.MODIFIERS_PROPERTY || isAnnotationsProperty) { |
| ASTNode parent = node.getParent(); |
| if (parent instanceof MethodDeclaration) |
| formatterPrefix= this.formatter.PARAM_ANNOTATION_SEPARATION; |
| else if (parent instanceof Block || parent instanceof TryStatement || parent instanceof ForStatement) |
| formatterPrefix= this.formatter.LOCAL_ANNOTATION_SEPARATION; |
| else |
| formatterPrefix= this.formatter.TYPE_ANNOTATION_SEPARATION; |
| } else { |
| formatterPrefix= this.formatter.ANNOTATION_SEPARATION; |
| } |
| |
| int endPos= new ModifierRewriter(formatterPrefix).rewriteList(node, property, pos, keyword, " "); //$NON-NLS-1$ |
| |
| try { |
| int nextPos= getScanner().getNextStartOffset(endPos, false); |
| RewriteEvent lastChild = children[children.length - 1]; |
| boolean lastUnchanged= lastChild.getChangeKind() != RewriteEvent.UNCHANGED; |
| |
| if (isAllRemove) { |
| doTextRemove(endPos, nextPos - endPos, getEditGroup(lastChild)); |
| return nextPos; |
| } else if ((isAllInsert || (nextPos == endPos && lastUnchanged)) // see bug 165654 |
| && !isVarargsAnnotationsProperty) { |
| String separator; |
| if (lastChild.getNewValue() instanceof Annotation) { |
| separator= formatterPrefix.getPrefix(getIndent(pos)); |
| } else { |
| separator= String.valueOf(' '); |
| } |
| doTextInsert(endPos, separator, getEditGroup(lastChild)); |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return endPos; |
| } |
| |
| private int rewriteTypeAnnotations(ASTNode node, ChildListPropertyDescriptor property, int pos) { |
| return rewriteModifiers2(node, property, pos); |
| } |
| |
| private int rewriteVarargsAnnotations(ASTNode node, ChildListPropertyDescriptor property, int pos) { |
| return rewriteModifiers2(node, property, pos); |
| } |
| |
| private void replaceOperation(int posBeforeOperation, String newOperation, TextEditGroup editGroup) { |
| try { |
| getScanner().readNext(posBeforeOperation, true); |
| doTextReplace(getScanner().getCurrentStartOffset(), getScanner().getCurrentLength(), newOperation, editGroup); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| |
| private void rewriteOperation(ASTNode parent, StructuralPropertyDescriptor property, int posBeforeOperation) { |
| RewriteEvent event= getEvent(parent, property); |
| if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { |
| try { |
| String newOperation= event.getNewValue().toString(); |
| TextEditGroup editGroup= getEditGroup(event); |
| getScanner().readNext(posBeforeOperation, true); |
| doTextReplace(getScanner().getCurrentStartOffset(), getScanner().getCurrentLength(), newOperation, editGroup); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| } |
| |
| @Override |
| public void postVisit(ASTNode node) { |
| TextEditGroup editGroup= this.eventStore.getTrackedNodeData(node); |
| if (editGroup != null) { |
| this.currentEdit= this.currentEdit.getParent(); |
| } |
| // remove copy source edits |
| doCopySourcePostVisit(node, this.sourceCopyEndNodes); |
| } |
| |
| @Override |
| public void preVisit(ASTNode node) { |
| // copies, then range marker |
| |
| CopySourceInfo[] infos= this.eventStore.getNodeCopySources(node); |
| doCopySourcePreVisit(infos, this.sourceCopyEndNodes); |
| |
| TextEditGroup editGroup= this.eventStore.getTrackedNodeData(node); |
| if (editGroup != null) { |
| SourceRange range= getExtendedRange(node); |
| int offset= range.getStartPosition(); |
| int length= range.getLength(); |
| TextEdit edit= new RangeMarker(offset, length); |
| addEditGroup(editGroup, edit); |
| addEdit(edit); |
| this.currentEdit= edit; |
| } |
| |
| ensureSpaceBeforeReplace(node); |
| } |
| |
| final void doCopySourcePreVisit(CopySourceInfo[] infos, Stack nodeEndStack) { |
| if (infos != null) { |
| for (int i= 0; i < infos.length; i++) { |
| CopySourceInfo curr= infos[i]; |
| TextEdit edit= getCopySourceEdit(curr); |
| addEdit(edit); |
| this.currentEdit= edit; |
| nodeEndStack.push(curr.getNode()); |
| } |
| } |
| } |
| |
| final void doCopySourcePostVisit(ASTNode node, Stack nodeEndStack) { |
| while (!nodeEndStack.isEmpty() && nodeEndStack.peek() == node) { |
| nodeEndStack.pop(); |
| this.currentEdit= this.currentEdit.getParent(); |
| } |
| } |
| |
| @Override |
| public boolean visit(CompilationUnit node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int startPos = 0; |
| boolean isModuleInfo = node.getAST().apiLevel() >= JLS9_INTERNAL && node.getModule() != null; |
| |
| if (!isModuleInfo) { |
| startPos = rewriteNode(node, CompilationUnit.PACKAGE_PROPERTY, 0, ASTRewriteFormatter.NONE); |
| |
| if (getChangeKind(node, CompilationUnit.PACKAGE_PROPERTY) == RewriteEvent.INSERTED) { |
| doTextInsert(0, getLineDelimiter(), getEditGroup(node, CompilationUnit.PACKAGE_PROPERTY)); |
| } |
| } |
| |
| startPos = rewriteParagraphList(node, CompilationUnit.IMPORTS_PROPERTY, startPos, 0, 0, 2); |
| if (isModuleInfo) { |
| rewriteNode(node, CompilationUnit.MODULE_PROPERTY, startPos, ASTRewriteFormatter.NONE); |
| } else { |
| rewriteParagraphList(node, CompilationUnit.TYPES_PROPERTY, startPos, 0, -1, 2); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(TypeDeclaration node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int apiLevel= node.getAST().apiLevel(); |
| |
| int pos= rewriteJavadoc(node, TypeDeclaration.JAVADOC_PROPERTY); |
| |
| boolean isJLS2 = apiLevel == JLS2_INTERNAL; |
| if (isJLS2) { |
| rewriteModifiers(node, INTERNAL_TYPE_MODIFIERS_PROPERTY, pos); |
| } else { |
| rewriteModifiers2(node, TypeDeclaration.MODIFIERS2_PROPERTY, pos); |
| } |
| |
| boolean isInterface= ((Boolean) getOriginalValue(node, TypeDeclaration.INTERFACE_PROPERTY)).booleanValue(); |
| // modifiers & class/interface |
| boolean invertType= isChanged(node, TypeDeclaration.INTERFACE_PROPERTY); |
| if (invertType) { |
| try { |
| int typeToken= isInterface ? TerminalTokens.TokenNameinterface : TerminalTokens.TokenNameclass; |
| int startPosition = node.getStartPosition(); |
| if (!isJLS2) { |
| List modifiers = node.modifiers(); |
| final int size = modifiers.size(); |
| if (size != 0) { |
| ASTNode modifierNode = (ASTNode) modifiers.get(size - 1); |
| startPosition = modifierNode.getStartPosition() + modifierNode.getLength(); |
| } |
| } |
| getScanner().readToToken(typeToken, startPosition); |
| |
| String str= isInterface ? "class" : "interface"; //$NON-NLS-1$ //$NON-NLS-2$ |
| int start= getScanner().getCurrentStartOffset(); |
| int end= getScanner().getCurrentEndOffset(); |
| |
| doTextReplace(start, end - start, str, getEditGroup(node, TypeDeclaration.INTERFACE_PROPERTY)); |
| } catch (CoreException e) { |
| // ignore |
| } |
| } |
| |
| // name |
| pos= rewriteRequiredNode(node, TypeDeclaration.NAME_PROPERTY); |
| |
| if (!isJLS2) { |
| pos= rewriteOptionalTypeParameters(node, TypeDeclaration.TYPE_PARAMETERS_PROPERTY, pos, Util.EMPTY_STRING, false, true); |
| } |
| |
| // superclass |
| if (!isInterface || invertType) { |
| ChildPropertyDescriptor superClassProperty= isJLS2 ? INTERNAL_TYPE_SUPERCLASS_PROPERTY : TypeDeclaration.SUPERCLASS_TYPE_PROPERTY; |
| |
| RewriteEvent superClassEvent= getEvent(node, superClassProperty); |
| |
| int changeKind= superClassEvent != null ? superClassEvent.getChangeKind() : RewriteEvent.UNCHANGED; |
| switch (changeKind) { |
| case RewriteEvent.INSERTED: { |
| doTextInsert(pos, " extends ", getEditGroup(superClassEvent)); //$NON-NLS-1$ |
| doTextInsert(pos, (ASTNode) superClassEvent.getNewValue(), 0, false, getEditGroup(superClassEvent)); |
| break; |
| } |
| case RewriteEvent.REMOVED: { |
| ASTNode superClass= (ASTNode) superClassEvent.getOriginalValue(); |
| int endPos= getExtendedEnd(superClass); |
| doTextRemoveAndVisit(pos, endPos - pos, superClass, getEditGroup(superClassEvent)); |
| pos= endPos; |
| break; |
| } |
| case RewriteEvent.REPLACED: { |
| ASTNode superClass= (ASTNode) superClassEvent.getOriginalValue(); |
| SourceRange range= getExtendedRange(superClass); |
| int offset= range.getStartPosition(); |
| int length= range.getLength(); |
| doTextRemoveAndVisit(offset, length, superClass, getEditGroup(superClassEvent)); |
| doTextInsert(offset, (ASTNode) superClassEvent.getNewValue(), 0, false, getEditGroup(superClassEvent)); |
| pos= offset + length; |
| break; |
| } |
| case RewriteEvent.UNCHANGED: { |
| pos= doVisit(node, superClassProperty, pos); |
| } |
| } |
| } |
| // extended interfaces |
| ChildListPropertyDescriptor superInterfaceProperty= isJLS2 ? INTERNAL_TYPE_SUPER_INTERFACES_PROPERTY : TypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY; |
| |
| RewriteEvent interfaceEvent= getEvent(node, superInterfaceProperty); |
| if (interfaceEvent == null || interfaceEvent.getChangeKind() == RewriteEvent.UNCHANGED) { |
| if (invertType) { |
| List originalNodes= (List) getOriginalValue(node, superInterfaceProperty); |
| if (!originalNodes.isEmpty()) { |
| String keyword= isInterface ? " implements " : " extends "; //$NON-NLS-1$ //$NON-NLS-2$ |
| ASTNode firstNode= (ASTNode) originalNodes.get(0); |
| doTextReplace(pos, firstNode.getStartPosition() - pos, keyword, getEditGroup(node, TypeDeclaration.INTERFACE_PROPERTY)); |
| } |
| } |
| pos= doVisit(node, superInterfaceProperty, pos); |
| } else { |
| String keyword= (isInterface == invertType) ? " implements " : " extends "; //$NON-NLS-1$ //$NON-NLS-2$ |
| if (invertType) { |
| List newNodes= (List) interfaceEvent.getNewValue(); |
| if (!newNodes.isEmpty()) { |
| List origNodes= (List) interfaceEvent.getOriginalValue(); |
| int firstStart= pos; |
| if (!origNodes.isEmpty()) { |
| firstStart= ((ASTNode) origNodes.get(0)).getStartPosition(); |
| } |
| doTextReplace(pos, firstStart - pos, keyword, getEditGroup(node, TypeDeclaration.INTERFACE_PROPERTY)); |
| keyword= Util.EMPTY_STRING; |
| pos= firstStart; |
| } |
| } |
| pos= rewriteNodeList(node, superInterfaceProperty, pos, keyword, ", "); //$NON-NLS-1$ |
| } |
| |
| // type members |
| // startPos : find position after left brace of type, be aware that bracket might be missing |
| int startIndent= getIndent(node.getStartPosition()) + 1; |
| int startPos= getPosAfterLeftBrace(pos); |
| rewriteParagraphList(node, TypeDeclaration.BODY_DECLARATIONS_PROPERTY, startPos, startIndent, -1, 2); |
| return false; |
| } |
| |
| private void rewriteReturnType(MethodDeclaration node, boolean isConstructor, boolean isConstructorChange) { |
| ChildPropertyDescriptor property= (node.getAST().apiLevel() == JLS2_INTERNAL) ? INTERNAL_METHOD_RETURN_TYPE_PROPERTY : MethodDeclaration.RETURN_TYPE2_PROPERTY; |
| |
| // weakness in the AST: return type can exist, even if missing in source |
| ASTNode originalReturnType= (ASTNode) getOriginalValue(node, property); |
| boolean returnTypeExists= originalReturnType != null && originalReturnType.getStartPosition() != -1; |
| if (!isConstructorChange && returnTypeExists) { |
| rewriteRequiredNode(node, property); |
| ensureSpaceAfterReplace(node, property); |
| return; |
| } |
| // difficult cases: return type insert or remove |
| ASTNode newReturnType= (ASTNode) getNewValue(node, property); |
| if (isConstructorChange || !returnTypeExists && newReturnType != originalReturnType) { |
| // use the start offset of the method name to insert |
| ASTNode originalMethodName= (ASTNode) getOriginalValue(node, MethodDeclaration.NAME_PROPERTY); |
| int nextStart= originalMethodName.getStartPosition(); // see bug 84049: can't use extended offset |
| TextEditGroup editGroup= getEditGroup(node, property); |
| if (isConstructor || !returnTypeExists) { // insert |
| doTextInsert(nextStart, newReturnType, getIndent(nextStart), true, editGroup); |
| doTextInsert(nextStart, " ", editGroup); //$NON-NLS-1$ |
| } else { // remove up to the method name |
| int offset= getExtendedOffset(originalReturnType); |
| doTextRemoveAndVisit(offset, nextStart - offset, originalReturnType, editGroup); |
| } |
| } |
| } |
| |
| private int rewriteMethodReceiver(MethodDeclaration method, int offset) throws CoreException { |
| offset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, offset); |
| if (method.getAST().apiLevel() < JLS8_INTERNAL) { |
| return offset; |
| } |
| |
| int newParamCount = ((List) getNewValue(method, MethodDeclaration.PARAMETERS_PROPERTY)).size(); |
| int oldParamCount = method.parameters().size(); |
| RewriteEvent event = getEvent(method, MethodDeclaration.RECEIVER_TYPE_PROPERTY); |
| RewriteEvent qualEvent = getEvent(method, MethodDeclaration.RECEIVER_QUALIFIER_PROPERTY); |
| |
| boolean rewriteQualifier = false; |
| ASTNode newQual = null; |
| ASTNode oldQual = null; |
| if (qualEvent != null) { |
| newQual = (ASTNode) qualEvent.getNewValue(); |
| oldQual = (ASTNode) qualEvent.getOriginalValue(); |
| } |
| |
| TextEditGroup editGroup= getEditGroup(event); |
| if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { |
| int changeKind= event.getChangeKind(); |
| if (changeKind == RewriteEvent.INSERTED) { |
| doTextInsert(offset, (ASTNode) event.getNewValue(), 0, false, editGroup); |
| doTextInsert(offset, " ", editGroup); //$NON-NLS-1$ |
| if (newQual != null ) { |
| doTextInsert(offset, newQual, 0, false, getEditGroup(qualEvent)); |
| doTextInsert(offset, ".", editGroup); //$NON-NLS-1$ |
| } |
| doTextInsert(offset, "this", editGroup); //$NON-NLS-1$ |
| if (newParamCount > 0) { |
| doTextInsert(offset, ", ", editGroup); //$NON-NLS-1$ |
| } |
| } else { |
| ASTNode elem= (ASTNode) event.getOriginalValue(); |
| SourceRange range= getExtendedRange(elem); |
| int elemOffset= range.getStartPosition(); |
| int elemLength= range.getLength(); |
| int elemEnd= elemOffset + elemLength; |
| if (changeKind == RewriteEvent.REMOVED) { |
| editGroup= getEditGroup(event); |
| int endPos; |
| if (oldParamCount == 0) { |
| endPos= getScanner().getTokenStartOffset(TerminalTokens.TokenNameRPAREN, elemEnd); |
| } else { |
| endPos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameCOMMA, elemEnd); |
| } |
| doTextRemoveAndVisit(offset, endPos - offset, elem, editGroup); |
| return endPos; |
| } else if (changeKind == RewriteEvent.REPLACED) { |
| editGroup= getEditGroup(event); |
| doTextRemoveAndVisit(elemOffset, elemLength, elem, editGroup); |
| doTextInsert(elemOffset, (ASTNode) event.getNewValue(), 0, false, editGroup); |
| rewriteQualifier = true; |
| } |
| } |
| } else { |
| rewriteRequiredNode(method, MethodDeclaration.RECEIVER_TYPE_PROPERTY); |
| if (method.getReceiverType() != null) { |
| rewriteQualifier = true; |
| } |
| } |
| if (rewriteQualifier) { |
| if (qualEvent != null) { |
| int qualChangeKind = qualEvent.getChangeKind(); |
| TextEditGroup qualGroup = getEditGroup(qualEvent); |
| if (qualChangeKind == RewriteEvent.INSERTED) { |
| int pos= getScanner().getTokenStartOffset(TerminalTokens.TokenNamethis, offset); |
| doTextInsert(pos, (ASTNode) qualEvent.getNewValue(), 0, false, qualGroup); |
| doTextInsert(pos, ".", qualGroup); //$NON-NLS-1$ |
| } else if (qualChangeKind == RewriteEvent.REMOVED) { |
| int qualOffset = oldQual.getStartPosition(); |
| int endPos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameDOT, qualOffset); |
| doTextRemove(qualOffset, endPos - qualOffset, qualGroup); |
| } else if (qualChangeKind == RewriteEvent.REPLACED) { |
| SourceRange range= getExtendedRange(oldQual); |
| int elemOffset= range.getStartPosition(); |
| int elemLength= range.getLength(); |
| doTextRemoveAndVisit(elemOffset, elemLength, oldQual, qualGroup); |
| doTextInsert(elemOffset, newQual, 0, false, qualGroup); |
| } |
| } |
| offset= getScanner().getTokenEndOffset(TerminalTokens.TokenNamethis, offset); |
| if (newParamCount > 0 && oldParamCount == 0) { |
| doTextInsert(offset, ", ", editGroup); //$NON-NLS-1$ |
| } |
| } |
| return offset; |
| } |
| |
| private ASTNode getPreviousNode(ASTNode node) { |
| ArrayType arrayType = (ArrayType) node.getParent(); |
| ASTNode prev = arrayType.getElementType(); |
| List l = (List) node.getParent().getStructuralProperty(node.getLocationInParent()); |
| int size = l.size(); |
| int i = 0; |
| for (; i < size; i++) { |
| ASTNode currNode = (ASTNode) l.get(i); |
| if (node == currNode) break; |
| prev = currNode; |
| } |
| return i < size ? prev : null; |
| } |
| |
| private int getPreviousTokenEndOffset(ASTNode node, int token) { |
| int offset = -1; |
| ASTNode prev = getPreviousNode(node); |
| if (prev != null) { |
| offset = prev.getStartPosition() + prev.getLength(); |
| try { |
| offset = getScanner().getPreviousTokenEndOffset(token, offset); |
| } catch (CoreException e1) { |
| e1.printStackTrace(); |
| } |
| } |
| return offset; |
| } |
| |
| @Override |
| public boolean visit(Dimension node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| boolean keywordSpace = true; |
| ASTNode parent = node.getParent(); |
| if (parent.getNodeType() == ASTNode.ARRAY_TYPE) { |
| List oldAnnotations = (List) getOriginalValue(node, Dimension.ANNOTATIONS_PROPERTY); |
| List newAnnotations = (List) getNewValue(node, Dimension.ANNOTATIONS_PROPERTY); |
| int oldAnnotationSize = oldAnnotations.size(); |
| int newAnnotationSize = newAnnotations.size(); |
| if (oldAnnotationSize > 0 && newAnnotationSize == 0) { /* removed all annotations */ |
| int delStart = getPreviousTokenEndOffset(node, TerminalTokens.TokenNameAT); |
| int delEnd = ((ASTNode) oldAnnotations.get(0)).getStartPosition(); |
| if (delStart >= 0 && delEnd > delStart) { |
| doTextRemove(delStart, delEnd - delStart, null); /* remove spaces before the annotation */ |
| } |
| |
| ASTNode currNode = (ASTNode) oldAnnotations.get(oldAnnotationSize - 1); |
| delStart = currNode.getStartPosition() + currNode.getLength(); |
| try { |
| delEnd = getScanner().getNextStartOffset(delStart, false); |
| doTextRemove(delStart, delEnd - delStart, null); /* remove spaces after the annotation */ |
| } catch (CoreException e) { |
| e.printStackTrace(); |
| } |
| } else if (oldAnnotationSize == 0 && newAnnotationSize > 0) { /* inserting first annotation */ |
| if (ScannerHelper.isWhitespace(this.content[node.getStartPosition() - 1])) { |
| keywordSpace = false; /* space exists already */ |
| } |
| } |
| } |
| rewriteNodeList(node, Dimension.ANNOTATIONS_PROPERTY, node.getStartPosition(), keywordSpace ? String.valueOf(' ') : Util.EMPTY_STRING, String.valueOf(' '), String.valueOf(' ')); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(MethodDeclaration node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteJavadoc(node, MethodDeclaration.JAVADOC_PROPERTY); |
| int apiLevel= node.getAST().apiLevel(); |
| if (apiLevel == JLS2_INTERNAL) { |
| rewriteModifiers(node, INTERNAL_METHOD_MODIFIERS_PROPERTY2, pos); |
| } else { |
| pos= rewriteModifiers2(node, MethodDeclaration.MODIFIERS2_PROPERTY, pos); |
| pos= rewriteOptionalTypeParameters(node, MethodDeclaration.TYPE_PARAMETERS_PROPERTY, pos, " ", true, pos != node.getStartPosition()); //$NON-NLS-1$ |
| } |
| |
| boolean isConstructorChange= isChanged(node, MethodDeclaration.CONSTRUCTOR_PROPERTY); |
| boolean isConstructor= ((Boolean) getOriginalValue(node, MethodDeclaration.CONSTRUCTOR_PROPERTY)).booleanValue(); |
| if (!isConstructor || isConstructorChange) { |
| rewriteReturnType(node, isConstructor, isConstructorChange); |
| } |
| // method name |
| pos= rewriteRequiredNode(node, MethodDeclaration.NAME_PROPERTY); |
| |
| // parameters |
| try { |
| pos= rewriteMethodReceiver(node, pos); |
| pos= rewriteNodeList(node, MethodDeclaration.PARAMETERS_PROPERTY, pos, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| |
| pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRPAREN, pos); |
| ChildListPropertyDescriptor exceptionsProperty = apiLevel < JLS8_INTERNAL ? INTERNAL_METHOD_THROWN_EXCEPTIONS_PROPERTY : MethodDeclaration.THROWN_EXCEPTION_TYPES_PROPERTY; |
| |
| if (apiLevel < JLS8_INTERNAL) { |
| int extraDims= rewriteExtraDimensions(node, INTERNAL_METHOD_EXTRA_DIMENSIONS_PROPERTY, pos); |
| |
| boolean hasExceptionChanges= isChanged(node, exceptionsProperty); |
| |
| int bodyChangeKind= getChangeKind(node, MethodDeclaration.BODY_PROPERTY); |
| |
| if ((extraDims > 0) && (hasExceptionChanges || bodyChangeKind == RewriteEvent.INSERTED || bodyChangeKind == RewriteEvent.REMOVED)) { |
| int dim= ((Integer) getOriginalValue(node, INTERNAL_METHOD_EXTRA_DIMENSIONS_PROPERTY)).intValue(); |
| while (dim > 0) { |
| pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRBRACKET, pos); |
| dim--; |
| } |
| } |
| } else { |
| pos= rewriteExtraDimensionsInfo(node, pos, MethodDeclaration.EXTRA_DIMENSIONS2_PROPERTY); |
| } |
| |
| pos= rewriteNodeList(node, exceptionsProperty, pos, " throws ", ", "); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| rewriteMethodBody(node, pos); |
| } catch (CoreException e) { |
| // ignore |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ModuleDeclaration node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteJavadoc(node, ModuleDeclaration.JAVADOC_PROPERTY); |
| pos= rewriteModifiers2(node, ModuleDeclaration.ANNOTATIONS_PROPERTY, pos); |
| |
| RewriteEvent event= getEvent(node, ModuleDeclaration.OPEN_PROPERTY); |
| if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { |
| boolean fakeInModule = getScanner().getScanner().fakeInModule; |
| try { |
| boolean wasOpen= ((Boolean) event.getOriginalValue()).booleanValue(); |
| if (wasOpen) { |
| this.tokenScanner.getScanner().fakeInModule = true; |
| int endPos= getScanner().getTokenStartOffset(TerminalTokens.TokenNamemodule, pos); |
| doTextRemove(pos, endPos - pos, getEditGroup(event)); |
| } else { |
| doTextInsert(pos, "open ", getEditGroup(event)); //$NON-NLS-1$ |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } finally { |
| this.tokenScanner.getScanner().fakeInModule = fakeInModule; |
| } |
| } |
| |
| pos= rewriteRequiredNode(node, ModuleDeclaration.NAME_PROPERTY); |
| int startPos = getPosAfterLeftBrace(pos); |
| int startIndent= getIndent(node.getStartPosition()) + 1; |
| boolean fakeInModule = this.tokenScanner.getScanner().fakeInModule; |
| this.tokenScanner.getScanner().fakeInModule = true; |
| rewriteParagraphList(node, ModuleDeclaration.MODULE_DIRECTIVES_PROPERTY, startPos, startIndent, 0, 1); |
| this.tokenScanner.getScanner().fakeInModule = fakeInModule; |
| return false; |
| } |
| |
| @Override |
| public boolean visit(Block node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int startPos; |
| if (isCollapsed(node)) { |
| startPos= node.getStartPosition(); |
| } else { |
| startPos= getPosAfterLeftBrace(node.getStartPosition()); |
| } |
| int startIndent= getIndent(node.getStartPosition()) + 1; |
| rewriteParagraphList(node, Block.STATEMENTS_PROPERTY, startPos, startIndent, 0, 1); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ReturnStatement node) { |
| try { |
| this.beforeRequiredSpaceIndex = getScanner().getTokenEndOffset(TerminalTokens.TokenNamereturn, node.getStartPosition()); |
| |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| ensureSpaceBeforeReplace(node); |
| |
| rewriteNode(node, ReturnStatement.EXPRESSION_PROPERTY, this.beforeRequiredSpaceIndex, ASTRewriteFormatter.SPACE); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(RequiresDirective node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos = getPosAfterToken(node.getStartPosition(), TerminalTokens.TokenNamerequires); |
| rewriteNodeList(node, RequiresDirective.MODIFIERS_PROPERTY, pos, String.valueOf(' '), String.valueOf(' ')); |
| rewriteRequiredNode(node, RequiresDirective.NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(AnonymousClassDeclaration node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int startPos= getPosAfterLeftBrace(node.getStartPosition()); |
| int startIndent= getIndent(node.getStartPosition()) + 1; |
| rewriteParagraphList(node, AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY, startPos, startIndent, -1, 2); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ArrayAccess node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteRequiredNode(node, ArrayAccess.ARRAY_PROPERTY); |
| rewriteRequiredNode(node, ArrayAccess.INDEX_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ArrayCreation node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| ArrayType arrayType= (ArrayType) getOriginalValue(node, ArrayCreation.TYPE_PROPERTY); |
| ArrayType replacingType= arrayType; |
| int nOldBrackets= getDimensions(arrayType); // number of total brackets |
| boolean astLevelGTE8 = node.getAST().apiLevel() >= JLS8_INTERNAL; |
| boolean typeReplaced = false; |
| |
| TextEditGroup editGroup= null; |
| RewriteEvent typeEvent= getEvent(node, ArrayCreation.TYPE_PROPERTY); |
| if (typeEvent != null && typeEvent.getChangeKind() == RewriteEvent.REPLACED) { // changed arraytype can have different dimension or type name |
| typeReplaced = true; |
| replacingType= (ArrayType) typeEvent.getNewValue(); |
| editGroup= getEditGroup(typeEvent); |
| Type newType= replacingType.getElementType(); |
| Type oldType= getElementType(arrayType); |
| if (!newType.equals(oldType)) { |
| SourceRange range= getExtendedRange(oldType); |
| int offset= range.getStartPosition(); |
| int length= range.getLength(); |
| doTextRemove(offset, length, editGroup); |
| doTextInsert(offset, newType, 0, false, editGroup); |
| } |
| } |
| |
| try { |
| // dimension node with expressions and/or annotations |
| RewriteEvent dimEvent= getEvent(node, ArrayCreation.DIMENSIONS_PROPERTY); |
| boolean hasDimensionChanges= (dimEvent != null && dimEvent.getChangeKind() != RewriteEvent.UNCHANGED); |
| RewriteEvent[] events= hasDimensionChanges ? dimEvent.getChildren() : null; |
| ArrayType currentLevel = astLevelGTE8 ? null : (ArrayType) replacingType.getElementType().getParent(); |
| int replacingTypeDimensions = replacingType.getDimensions(); |
| int i=0, dimSize= (events == null) ? 0 : events.length; |
| Type elementType= arrayType.getElementType(); |
| int offset= elementType.getStartPosition() + elementType.getLength(); |
| editGroup = null; |
| while(currentLevel != null || astLevelGTE8) { |
| if (i < dimSize) { |
| if (astLevelGTE8) |
| rewriteAnnotationsOnDimension(arrayType, replacingType, i, offset, typeReplaced, editGroup); |
| offset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLBRACKET, offset); |
| if (hasDimensionChanges) { |
| RewriteEvent event= events[i]; |
| int changeKind= event.getChangeKind(); |
| if (changeKind == RewriteEvent.INSERTED) { // insert new dimension |
| editGroup= getEditGroup(event); |
| int endPos= getScanner().getTokenStartOffset(TerminalTokens.TokenNameRBRACKET, offset); |
| doTextRemove(offset, endPos - offset, editGroup); |
| doTextInsert(offset, (ASTNode) event.getNewValue(), 0, false, editGroup); |
| } else { |
| ASTNode elem= (ASTNode) event.getOriginalValue(); |
| int elemEnd= elem.getStartPosition() + elem.getLength(); |
| int endPos= getScanner().getTokenStartOffset(TerminalTokens.TokenNameRBRACKET, elemEnd); |
| if (changeKind == RewriteEvent.REMOVED) { |
| editGroup= getEditGroup(event); |
| doTextRemoveAndVisit(offset, endPos - offset, elem, editGroup); |
| } else if (changeKind == RewriteEvent.REPLACED) { |
| editGroup= getEditGroup(event); |
| SourceRange range= getExtendedRange(elem); |
| int elemOffset= range.getStartPosition(); |
| int elemLength= range.getLength(); |
| doTextRemoveAndVisit(elemOffset, elemLength, elem, editGroup); |
| doTextInsert(elemOffset, (ASTNode) event.getNewValue(), 0, false, editGroup); |
| } else { |
| voidVisit(elem); |
| } |
| } |
| offset= retrieveRightBracketEndPosition(offset, 1, true); |
| } else { |
| ASTNode elem= (ASTNode) node.dimensions().get(i); |
| voidVisit(elem); |
| offset= retrieveRightBracketEndPosition(offset, 1, true); |
| } |
| } else if (i < nOldBrackets) { |
| if (astLevelGTE8) |
| rewriteAnnotationsOnDimension(arrayType, replacingType, i, offset, typeReplaced, editGroup); |
| offset= retrieveRightBracketEndPosition(offset, 1, false); |
| } else { |
| insertAnnotationsOnDimension(replacingType, i, offset, editGroup, astLevelGTE8); |
| doTextInsert(offset, "[]", editGroup); //$NON-NLS-1$ |
| } |
| i++; |
| if (astLevelGTE8) { |
| if (i == replacingTypeDimensions) break; |
| } else { |
| if (currentLevel == replacingType) break; |
| currentLevel= (ArrayType) currentLevel.getParent(); |
| } |
| } |
| if (i < nOldBrackets) { |
| int endPos= retrieveRightBracketEndPosition(offset, nOldBrackets - i, false); |
| doTextRemove(offset, endPos - offset, editGroup); |
| } |
| |
| int kind= getChangeKind(node, ArrayCreation.INITIALIZER_PROPERTY); |
| if (kind == RewriteEvent.REMOVED) { |
| offset= getScanner().getPreviousTokenEndOffset(TerminalTokens.TokenNameLBRACE, offset); |
| } else { |
| offset= node.getStartPosition() + node.getLength(); // insert pos |
| } |
| rewriteNode(node, ArrayCreation.INITIALIZER_PROPERTY, offset, ASTRewriteFormatter.SPACE); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return false; |
| } |
| |
| private void insertAnnotationsOnDimension(ArrayType replacingType, int index, int pos, TextEditGroup editGroup, |
| boolean astLevelGTE8) { |
| if (astLevelGTE8) { |
| Dimension dim = (Dimension) replacingType.dimensions().get(index); |
| List annotations = dim.annotations(); |
| if (annotations != null) { |
| int size = annotations.size(); |
| if (size > 0) { |
| doTextInsert(pos, " ", editGroup); //$NON-NLS-1$ |
| for (int j = 0; j < size; j++) { |
| Annotation annotation = (Annotation) annotations.get(j); |
| doTextInsert(pos, annotation.toString() + " ", editGroup); //$NON-NLS-1$ |
| } |
| } |
| } |
| } |
| } |
| |
| private void rewriteAnnotationsOnDimension(ArrayType oldArrayType, ArrayType replacingType, int index, int pos, boolean typeReplaced, TextEditGroup editGroup) throws CoreException { |
| if (typeReplaced) { |
| List dimensions = oldArrayType.dimensions(); |
| Dimension oldDim = index < dimensions.size() ? (Dimension) dimensions.get(index) : null; |
| if (oldDim != null) { |
| List oldAnnotations = oldDim.annotations(); |
| int size = oldAnnotations.size(); |
| if (size > 0) { |
| ASTNode prev = getPreviousNode(oldDim); |
| Annotation annotation = (Annotation) oldAnnotations.get(0); |
| int start = prev != null ? prev.getStartPosition() + prev.getLength() : annotation.getStartPosition(); |
| annotation = (Annotation) oldAnnotations.get(size - 1); |
| int end = annotation.getStartPosition() + annotation.getLength(); |
| end = getScanner().getTokenEndOffset(TerminalTokens.TokenNameLBRACKET, end) - 1; |
| doTextRemove(start, end - start, editGroup); |
| } |
| } |
| insertAnnotationsOnDimension(replacingType, index, pos, editGroup, true); |
| } else { |
| Dimension dim = (Dimension) replacingType.dimensions().get(index); |
| rewriteNodeList(dim, Dimension.ANNOTATIONS_PROPERTY, pos, String.valueOf(' '), String.valueOf(' '), String.valueOf(' ')); |
| } |
| } |
| |
| /** |
| * This method is used to retrieve the position of the right bracket. |
| * @return int the dimension found, -1 if none |
| */ |
| protected int retrieveRightBracketEndPosition(int offset, int count, boolean isLeftRead) throws CoreException { |
| TokenScanner scanner= getScanner(); |
| int token; |
| int balance= 0; |
| if (isLeftRead) balance++; |
| scanner.setOffset(offset); |
| while ((token= scanner.readNext(true)) != TerminalTokens.TokenNameEOF) { |
| switch(token) { |
| case TerminalTokens.TokenNameLBRACKET : |
| balance++; |
| break; |
| case TerminalTokens.TokenNameRBRACKET : |
| balance--; |
| if (balance == 0) { |
| if (--count == 0) { |
| return scanner.getCurrentEndOffset(); |
| } |
| } |
| break; |
| } |
| } |
| return -1; |
| } |
| |
| private Type getElementType(ArrayType parent) { |
| if (parent.getAST().apiLevel() >= JLS8_INTERNAL) { |
| return (Type) getOriginalValue(parent, ArrayType.ELEMENT_TYPE_PROPERTY); |
| } |
| Type t = (Type) getOriginalValue(parent, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY); |
| while (t.isArrayType()) { |
| t = (Type) getOriginalValue(t, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY); |
| } |
| return t; |
| } |
| |
| private int getDimensions(ArrayType parent) { |
| if (parent.getAST().apiLevel() >= JLS8_INTERNAL) { |
| return ((List) getOriginalValue(parent, ArrayType.DIMENSIONS_PROPERTY)).size(); |
| } |
| Type t = (Type) getOriginalValue(parent, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY); |
| int dimensions = 1; // always include this array type |
| while (t.isArrayType()) { |
| dimensions++; |
| t = (Type) getOriginalValue(t, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY); |
| } |
| return dimensions; |
| } |
| |
| @Override |
| public boolean visit(ArrayInitializer node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int startPos= getPosAfterLeftBrace(node.getStartPosition()); |
| rewriteNodeList(node, ArrayInitializer.EXPRESSIONS_PROPERTY, startPos, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| return false; |
| } |
| |
| private int rewriteArrayTypeDimensions(ArrayType node, int pos) { |
| return rewriteNodeList(node, ArrayType.DIMENSIONS_PROPERTY, pos, Util.EMPTY_STRING, ""); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public boolean visit(ArrayType node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| if (node.getAST().apiLevel() < JLS8_INTERNAL) { |
| rewriteRequiredNode(node, INTERNAL_ARRAY_COMPONENT_TYPE_PROPERTY); |
| } else { |
| int pos = rewriteRequiredNode(node, ArrayType.ELEMENT_TYPE_PROPERTY); |
| rewriteArrayTypeDimensions(node, pos); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(AssertStatement node) { |
| try { |
| this.beforeRequiredSpaceIndex = getScanner().getNextEndOffset(node.getStartPosition(), true); |
| |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| ensureSpaceBeforeReplace(node); |
| |
| int offset= rewriteRequiredNode(node, AssertStatement.EXPRESSION_PROPERTY); |
| rewriteNode(node, AssertStatement.MESSAGE_PROPERTY, offset, ASTRewriteFormatter.ASSERT_COMMENT); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(Assignment node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int pos= rewriteRequiredNode(node, Assignment.LEFT_HAND_SIDE_PROPERTY); |
| rewriteOperation(node, Assignment.OPERATOR_PROPERTY, pos); |
| rewriteRequiredNode(node, Assignment.RIGHT_HAND_SIDE_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(BooleanLiteral node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| Boolean newLiteral= (Boolean) getNewValue(node, BooleanLiteral.BOOLEAN_VALUE_PROPERTY); |
| TextEditGroup group = getEditGroup(node, BooleanLiteral.BOOLEAN_VALUE_PROPERTY); |
| doTextReplace(node.getStartPosition(), node.getLength(), newLiteral.toString(), group); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(BreakStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| try { |
| int offset= getScanner().getTokenEndOffset(TerminalTokens.TokenNamebreak, node.getStartPosition()); |
| rewriteNode(node, BreakStatement.LABEL_PROPERTY, offset, ASTRewriteFormatter.SPACE); // space between break and label |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(CastExpression node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteRequiredNode(node, CastExpression.TYPE_PROPERTY); |
| rewriteRequiredNode(node, CastExpression.EXPRESSION_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(CatchClause node) { // catch (Exception) Block |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteRequiredNode(node, CatchClause.EXCEPTION_PROPERTY); |
| rewriteRequiredNode(node, CatchClause.BODY_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(CharacterLiteral node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| String escapedSeq= (String) getNewValue(node, CharacterLiteral.ESCAPED_VALUE_PROPERTY); |
| TextEditGroup group = getEditGroup(node, CharacterLiteral.ESCAPED_VALUE_PROPERTY); |
| doTextReplace(node.getStartPosition(), node.getLength(), escapedSeq, group); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ClassInstanceCreation node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int pos= rewriteOptionalQualifier(node, ClassInstanceCreation.EXPRESSION_PROPERTY, node.getStartPosition()); |
| if (node.getAST().apiLevel() == JLS2_INTERNAL) { |
| pos= rewriteRequiredNode(node, INTERNAL_CIC_NAME_PROPERTY); |
| } else { |
| if (isChanged(node, ClassInstanceCreation.TYPE_ARGUMENTS_PROPERTY)) { |
| try { |
| pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNamenew, pos); //after 'new' |
| rewriteOptionalTypeParameters(node, ClassInstanceCreation.TYPE_ARGUMENTS_PROPERTY, pos, " ", true, true); //$NON-NLS-1$ |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| voidVisit(node, ClassInstanceCreation.TYPE_ARGUMENTS_PROPERTY); |
| } |
| pos= rewriteRequiredNode(node, ClassInstanceCreation.TYPE_PROPERTY); |
| } |
| |
| if (isChanged(node, ClassInstanceCreation.ARGUMENTS_PROPERTY)) { |
| try { |
| int startpos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); |
| rewriteNodeList(node, ClassInstanceCreation.ARGUMENTS_PROPERTY, startpos, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| voidVisit(node, ClassInstanceCreation.ARGUMENTS_PROPERTY); |
| } |
| |
| int kind= getChangeKind(node, ClassInstanceCreation.ANONYMOUS_CLASS_DECLARATION_PROPERTY); |
| if (kind == RewriteEvent.REMOVED) { |
| try { |
| pos= getScanner().getPreviousTokenEndOffset(TerminalTokens.TokenNameLBRACE, pos); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| pos= node.getStartPosition() + node.getLength(); // insert pos |
| } |
| rewriteNode(node, ClassInstanceCreation.ANONYMOUS_CLASS_DECLARATION_PROPERTY, pos, ASTRewriteFormatter.SPACE); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ConditionalExpression node) { // expression ? thenExpression : elseExpression |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteRequiredNode(node, ConditionalExpression.EXPRESSION_PROPERTY); |
| rewriteRequiredNode(node, ConditionalExpression.THEN_EXPRESSION_PROPERTY); |
| rewriteRequiredNode(node, ConditionalExpression.ELSE_EXPRESSION_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ConstructorInvocation node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= node.getStartPosition(); |
| if (node.getAST().apiLevel() >= JLS3_INTERNAL) { |
| pos= rewriteOptionalTypeParameters(node, ConstructorInvocation.TYPE_ARGUMENTS_PROPERTY, pos, Util.EMPTY_STRING, false, false); |
| } |
| try { |
| pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); |
| rewriteNodeList(node, ConstructorInvocation.ARGUMENTS_PROPERTY, pos, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ContinueStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| try { |
| int offset= getScanner().getTokenEndOffset(TerminalTokens.TokenNamecontinue, node.getStartPosition()); |
| rewriteNode(node, ContinueStatement.LABEL_PROPERTY, offset, ASTRewriteFormatter.SPACE); // space between continue and label |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return false; |
| } |
| |
| private void visitReferenceTypeArguments(ASTNode node, StructuralPropertyDescriptor childProperty, int pos) { |
| if (isChanged(node, childProperty)) { |
| try { |
| pos = getScanner().getTokenEndOffset(TerminalTokens.TokenNameCOLON_COLON, pos); |
| rewriteOptionalTypeParameters(node, childProperty, pos, Util.EMPTY_STRING, false, false); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| } |
| |
| @Override |
| public boolean visit(CreationReference node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteRequiredNode(node, CreationReference.TYPE_PROPERTY); |
| visitReferenceTypeArguments(node, CreationReference.TYPE_ARGUMENTS_PROPERTY, pos); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(DoStatement node) { // do statement while expression |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int pos= node.getStartPosition(); |
| try { |
| RewriteEvent event= getEvent(node, DoStatement.BODY_PROPERTY); |
| if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) { |
| int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNamedo, pos); |
| ASTNode body= (ASTNode) event.getOriginalValue(); |
| int bodyEnd= body.getStartPosition() + body.getLength(); |
| int endPos= getScanner().getTokenStartOffset(TerminalTokens.TokenNamewhile, bodyEnd); |
| rewriteBodyNode(node, DoStatement.BODY_PROPERTY, startOffset, endPos, getIndent(node.getStartPosition()), this.formatter.DO_BLOCK); // body |
| } else { |
| voidVisit(node, DoStatement.BODY_PROPERTY); |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| |
| rewriteRequiredNode(node, DoStatement.EXPRESSION_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(EmptyStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| changeNotSupported(node); // no modification possible |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ExportsDirective node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos = rewriteRequiredNode(node, ExportsDirective.NAME_PROPERTY); |
| rewriteNodeList(node, ExportsDirective.MODULES_PROPERTY, pos, "to ", ", "); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ExpressionStatement node) { // expression |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteRequiredNode(node, ExpressionStatement.EXPRESSION_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(FieldAccess node) { // expression.name |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteRequiredNode(node, FieldAccess.EXPRESSION_PROPERTY); // expression |
| rewriteRequiredNode(node, FieldAccess.NAME_PROPERTY); // name |
| return false; |
| } |
| |
| @Override |
| public boolean visit(FieldDeclaration node) { //{ Modifier } Type VariableDeclarationFragment { ',' VariableDeclarationFragment } ';' |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteJavadoc(node, FieldDeclaration.JAVADOC_PROPERTY); |
| |
| if (node.getAST().apiLevel() == JLS2_INTERNAL) { |
| rewriteModifiers(node, INTERNAL_FIELD_MODIFIERS_PROPERTY, pos); |
| } else { |
| rewriteModifiers2(node, FieldDeclaration.MODIFIERS2_PROPERTY, pos); |
| } |
| |
| pos= rewriteRequiredNode(node, FieldDeclaration.TYPE_PROPERTY); |
| ensureSpaceAfterReplace(node, FieldDeclaration.TYPE_PROPERTY); |
| rewriteNodeList(node, FieldDeclaration.FRAGMENTS_PROPERTY, pos, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ForStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| try { |
| int pos= node.getStartPosition(); |
| |
| if (isChanged(node, ForStatement.INITIALIZERS_PROPERTY)) { |
| // position after opening parent |
| int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); |
| pos= rewriteNodeList(node, ForStatement.INITIALIZERS_PROPERTY, startOffset, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| } else { |
| pos= doVisit(node, ForStatement.INITIALIZERS_PROPERTY, pos); |
| } |
| |
| // position after first semicolon |
| pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameSEMICOLON, pos); |
| |
| pos= rewriteNode(node, ForStatement.EXPRESSION_PROPERTY, pos, ASTRewriteFormatter.NONE); |
| |
| if (isChanged(node, ForStatement.UPDATERS_PROPERTY)) { |
| int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameSEMICOLON, pos); |
| pos= rewriteNodeList(node, ForStatement.UPDATERS_PROPERTY, startOffset, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| } else { |
| pos= doVisit(node, ForStatement.UPDATERS_PROPERTY, pos); |
| } |
| |
| RewriteEvent bodyEvent= getEvent(node, ForStatement.BODY_PROPERTY); |
| if (bodyEvent != null && bodyEvent.getChangeKind() == RewriteEvent.REPLACED) { |
| int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRPAREN, pos); |
| rewriteBodyNode(node, ForStatement.BODY_PROPERTY, startOffset, -1, getIndent(node.getStartPosition()), this.formatter.FOR_BLOCK); // body |
| } else { |
| voidVisit(node, ForStatement.BODY_PROPERTY); |
| } |
| |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| |
| |
| return false; |
| } |
| |
| @Override |
| public boolean visit(IfStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int pos= rewriteRequiredNode(node, IfStatement.EXPRESSION_PROPERTY); // statement |
| |
| RewriteEvent thenEvent= getEvent(node, IfStatement.THEN_STATEMENT_PROPERTY); |
| int elseChange= getChangeKind(node, IfStatement.ELSE_STATEMENT_PROPERTY); |
| |
| if (thenEvent != null && thenEvent.getChangeKind() != RewriteEvent.UNCHANGED) { |
| try { |
| int tok= getScanner().readNext(pos, true); // after the closing parent |
| pos= (tok == TerminalTokens.TokenNameRPAREN) ? getScanner().getCurrentEndOffset() : getScanner().getCurrentStartOffset(); |
| |
| int indent= getIndent(node.getStartPosition()); |
| |
| int endPos= -1; |
| Object elseStatement= getOriginalValue(node, IfStatement.ELSE_STATEMENT_PROPERTY); |
| if (elseStatement != null) { |
| ASTNode thenStatement = (ASTNode) thenEvent.getOriginalValue(); |
| endPos= getScanner().getTokenStartOffset(TerminalTokens.TokenNameelse, thenStatement.getStartPosition() + thenStatement.getLength()); // else keyword |
| } |
| if (elseStatement == null || elseChange != RewriteEvent.UNCHANGED) { |
| pos= rewriteBodyNode(node, IfStatement.THEN_STATEMENT_PROPERTY, pos, endPos, indent, this.formatter.IF_BLOCK_NO_ELSE); |
| } else { |
| pos= rewriteBodyNode(node, IfStatement.THEN_STATEMENT_PROPERTY, pos, endPos, indent, this.formatter.IF_BLOCK_WITH_ELSE); |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| pos= doVisit(node, IfStatement.THEN_STATEMENT_PROPERTY, pos); |
| } |
| |
| if (elseChange != RewriteEvent.UNCHANGED) { |
| int indent= getIndent(node.getStartPosition()); |
| Object newThen= getNewValue(node, IfStatement.THEN_STATEMENT_PROPERTY); |
| if (newThen instanceof Block) { |
| rewriteBodyNode(node, IfStatement.ELSE_STATEMENT_PROPERTY, pos, -1, indent, this.formatter.ELSE_AFTER_BLOCK); |
| } else { |
| rewriteBodyNode(node, IfStatement.ELSE_STATEMENT_PROPERTY, pos, -1, indent, this.formatter.ELSE_AFTER_STATEMENT); |
| } |
| } else { |
| pos= doVisit(node, IfStatement.ELSE_STATEMENT_PROPERTY, pos); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ImportDeclaration node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| if (node.getAST().apiLevel() >= JLS3_INTERNAL) { |
| RewriteEvent event= getEvent(node, ImportDeclaration.STATIC_PROPERTY); |
| if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { |
| try { |
| int pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameimport, node.getStartPosition()); |
| boolean wasStatic= ((Boolean) event.getOriginalValue()).booleanValue(); |
| if (wasStatic) { |
| int endPos= getScanner().getTokenEndOffset(TerminalTokens.TokenNamestatic, pos); |
| doTextRemove(pos, endPos - pos, getEditGroup(event)); |
| } else { |
| doTextInsert(pos, " static", getEditGroup(event)); //$NON-NLS-1$ |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| } |
| |
| int pos= rewriteRequiredNode(node, ImportDeclaration.NAME_PROPERTY); |
| |
| RewriteEvent event= getEvent(node, ImportDeclaration.ON_DEMAND_PROPERTY); |
| if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { |
| boolean isOnDemand= ((Boolean) event.getOriginalValue()).booleanValue(); |
| if (!isOnDemand) { |
| doTextInsert(pos, ".*", getEditGroup(event)); //$NON-NLS-1$ |
| } else { |
| try { |
| int endPos= getScanner().getTokenStartOffset(TerminalTokens.TokenNameSEMICOLON, pos); |
| doTextRemove(pos, endPos - pos, getEditGroup(event)); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(InfixExpression node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| Expression right= node.getRightOperand(); |
| int pos; |
| |
| RewriteEvent leftEvent= getEvent(node, InfixExpression.LEFT_OPERAND_PROPERTY); |
| boolean removeLeft = leftEvent != null && leftEvent.getChangeKind() == RewriteEvent.REMOVED; |
| RewriteEvent rightEvent= getEvent(node, InfixExpression.RIGHT_OPERAND_PROPERTY); |
| boolean removeRight = rightEvent != null && rightEvent.getChangeKind() == RewriteEvent.REMOVED; |
| |
| if (removeLeft) { |
| Expression left= node.getLeftOperand(); |
| int leftStart= getExtendedOffset(left); |
| pos= getExtendedOffset(right); |
| TextEditGroup editGroup= getEditGroup(leftEvent); |
| doTextRemoveAndVisit(leftStart, pos - leftStart, left, editGroup); |
| } else { |
| pos = rewriteRequiredNode(node, InfixExpression.LEFT_OPERAND_PROPERTY); |
| } |
| |
| boolean needsNewOperation= isChanged(node, InfixExpression.OPERATOR_PROPERTY); |
| String operation= getNewValue(node, InfixExpression.OPERATOR_PROPERTY).toString(); |
| if (needsNewOperation && !removeLeft && !removeRight) { |
| replaceOperation(pos, operation, getEditGroup(node, InfixExpression.OPERATOR_PROPERTY)); |
| } |
| |
| if (removeRight) { |
| int end; |
| if (removeLeft && node.extendedOperands().size() > 0) { |
| end= getExtendedOffset((Expression) node.extendedOperands().get(0)); |
| } else { |
| end= getExtendedEnd(right); |
| } |
| TextEditGroup editGroup= getEditGroup(rightEvent); |
| doTextRemoveAndVisit(pos, end - pos, right, editGroup); |
| pos= end; |
| } else { |
| pos= rewriteRequiredNode(node, InfixExpression.RIGHT_OPERAND_PROPERTY); |
| } |
| |
| RewriteEvent event= getEvent(node, InfixExpression.EXTENDED_OPERANDS_PROPERTY); |
| String prefixString= ' ' + operation + ' '; |
| |
| if (needsNewOperation) { |
| int startPos= pos; |
| TextEditGroup editGroup= getEditGroup(node, InfixExpression.OPERATOR_PROPERTY); |
| |
| if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { |
| RewriteEvent[] extendedOperands= event.getChildren(); |
| for (int i= 0; i < extendedOperands.length; i++) { |
| RewriteEvent curr= extendedOperands[i]; |
| ASTNode elem= (ASTNode) curr.getOriginalValue(); |
| if (elem != null) { |
| if (curr.getChangeKind() != RewriteEvent.REPLACED) { |
| replaceOperation(startPos, operation, editGroup); |
| } |
| startPos= elem.getStartPosition() + elem.getLength(); |
| } |
| } |
| } else { |
| List extendedOperands= (List) getOriginalValue(node, InfixExpression.EXTENDED_OPERANDS_PROPERTY); |
| for (int i= 0; i < extendedOperands.size(); i++) { |
| ASTNode elem= (ASTNode) extendedOperands.get(i); |
| replaceOperation(startPos, operation, editGroup); |
| startPos= elem.getStartPosition() + elem.getLength(); |
| } |
| } |
| } |
| rewriteNodeList(node, InfixExpression.EXTENDED_OPERANDS_PROPERTY, pos, prefixString, prefixString); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(Initializer node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteJavadoc(node, Initializer.JAVADOC_PROPERTY); |
| if (node.getAST().apiLevel() == JLS2_INTERNAL) { |
| rewriteModifiers(node, INTERNAL_INITIALIZER_MODIFIERS_PROPERTY3, pos); |
| } else { |
| rewriteModifiers2(node, Initializer.MODIFIERS2_PROPERTY, pos); |
| } |
| rewriteRequiredNode(node, Initializer.BODY_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(InstanceofExpression node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteRequiredNode(node, InstanceofExpression.LEFT_OPERAND_PROPERTY); |
| ensureSpaceAfterReplace(node, InstanceofExpression.LEFT_OPERAND_PROPERTY); |
| rewriteRequiredNode(node, InstanceofExpression.RIGHT_OPERAND_PROPERTY); |
| return false; |
| } |
| |
| private void ensureSpaceAfterReplace(ASTNode node, ChildPropertyDescriptor desc) { |
| if (getChangeKind(node, desc) == RewriteEvent.REPLACED) { |
| int leftOperandEnd= getExtendedEnd((ASTNode) getOriginalValue(node, desc)); |
| try { |
| int offset= getScanner().getNextStartOffset(leftOperandEnd, true); // instanceof |
| |
| if (offset == leftOperandEnd) { |
| doTextInsert(offset, String.valueOf(' '), getEditGroup(node, desc)); |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| } |
| |
| private void ensureSpaceBeforeReplace(ASTNode node) { |
| if (this.beforeRequiredSpaceIndex == -1) return; |
| |
| List events = this.eventStore.getChangedPropertieEvents(node); |
| |
| for (Iterator iterator = events.iterator(); iterator.hasNext();) { |
| RewriteEvent event = (RewriteEvent) iterator.next(); |
| if (event.getChangeKind() == RewriteEvent.REPLACED && event.getOriginalValue() instanceof ASTNode) { |
| if (this.beforeRequiredSpaceIndex == getExtendedOffset((ASTNode) event.getOriginalValue())) { |
| doTextInsert(this.beforeRequiredSpaceIndex , String.valueOf(' '), getEditGroup(event)); |
| this.beforeRequiredSpaceIndex = -1; |
| return; |
| } |
| } |
| } |
| |
| if (this.beforeRequiredSpaceIndex < getExtendedOffset(node)) { |
| this.beforeRequiredSpaceIndex = -1; |
| } |
| } |
| |
| @Override |
| public boolean visit(IntersectionType node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| rewriteNodeList(node, IntersectionType.TYPES_PROPERTY, node.getStartPosition(), Util.EMPTY_STRING, " & "); //$NON-NLS-1$ |
| return false; |
| } |
| |
| @Override |
| public boolean visit(Javadoc node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int startPos= node.getStartPosition() + 3; |
| String separator= getLineDelimiter() + getIndentAtOffset(node.getStartPosition()) + " * "; //$NON-NLS-1$ |
| |
| rewriteNodeList(node, Javadoc.TAGS_PROPERTY, startPos, separator, separator); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(LabeledStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteRequiredNode(node, LabeledStatement.LABEL_PROPERTY); |
| rewriteRequiredNode(node, LabeledStatement.BODY_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(LambdaExpression node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| Boolean newValue = (Boolean) getNewValue(node, LambdaExpression.PARENTHESES_PROPERTY); |
| boolean hasParentheses = newValue.equals(Boolean.TRUE); |
| if (!hasParentheses) {// Parentheses can be absent if and only if there is one and only one type elided parameter. |
| List parameters = (List) getNewValue(node, LambdaExpression.PARAMETERS_PROPERTY); |
| hasParentheses = !(parameters.size() == 1 && parameters.get(0) instanceof VariableDeclarationFragment); |
| } |
| |
| boolean deleteParentheses = false; |
| boolean insertParentheses = false; |
| TextEditGroup editGroup = null; |
| |
| boolean oldHasParentheses = getOriginalValue(node, LambdaExpression.PARENTHESES_PROPERTY).equals(Boolean.TRUE); |
| RewriteEvent event = getEvent(node, LambdaExpression.PARENTHESES_PROPERTY); |
| if (event != null) { |
| editGroup = getEditGroup(event); |
| if (event.getChangeKind() == RewriteEvent.REPLACED) { |
| if (newValue != Boolean.FALSE) { |
| insertParentheses = true; |
| } else {// apply the stricter check for parentheses deletion |
| deleteParentheses = !hasParentheses; |
| } |
| } |
| } else if (!oldHasParentheses && hasParentheses) {// parameter property changed to effect parentheses insertion |
| if ((event = getEvent(node, LambdaExpression.PARAMETERS_PROPERTY)) != null) {// a null check though event cannot be null here |
| editGroup = getEditGroup(event); |
| insertParentheses = true; |
| } |
| } |
| |
| int pos = node.getStartPosition(); |
| if (insertParentheses) { |
| doTextInsert(pos, "(", editGroup); //$NON-NLS-1$ |
| } else if (deleteParentheses) { |
| try { |
| int lparensEnd = getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); |
| doTextRemove(pos, lparensEnd - pos, editGroup); |
| pos = lparensEnd; |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| |
| if (isChanged(node, LambdaExpression.PARAMETERS_PROPERTY)) { |
| try { |
| pos = oldHasParentheses ? getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos) : pos; |
| pos = rewriteNodeList(node, LambdaExpression.PARAMETERS_PROPERTY, pos, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| pos = doVisit(node, LambdaExpression.PARAMETERS_PROPERTY, pos); |
| } |
| |
| if (insertParentheses) { |
| doTextInsert(pos, ")", editGroup); //$NON-NLS-1$ |
| } else if (deleteParentheses) { |
| try { |
| doTextRemove(pos, getScanner().getTokenEndOffset(TerminalTokens.TokenNameRPAREN, pos) - pos, editGroup); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| rewriteRequiredNode(node, LambdaExpression.BODY_PROPERTY); |
| |
| return false; |
| } |
| |
| @Override |
| public boolean visit(MethodInvocation node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int pos= rewriteOptionalQualifier(node, MethodInvocation.EXPRESSION_PROPERTY, node.getStartPosition()); |
| if (node.getAST().apiLevel() >= JLS3_INTERNAL) { |
| pos= rewriteOptionalTypeParameters(node, MethodInvocation.TYPE_ARGUMENTS_PROPERTY, pos, Util.EMPTY_STRING, false, false); |
| } |
| |
| pos= rewriteRequiredNode(node, MethodInvocation.NAME_PROPERTY); |
| |
| if (isChanged(node, MethodInvocation.ARGUMENTS_PROPERTY)) { |
| // eval position after opening parent |
| try { |
| int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); |
| rewriteNodeList(node, MethodInvocation.ARGUMENTS_PROPERTY, startOffset, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| voidVisit(node, MethodInvocation.ARGUMENTS_PROPERTY); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(NullLiteral node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| changeNotSupported(node); // no modification possible |
| return false; |
| } |
| |
| @Override |
| public boolean visit(NumberLiteral node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| String newLiteral= (String) getNewValue(node, NumberLiteral.TOKEN_PROPERTY); |
| TextEditGroup group = getEditGroup(node, NumberLiteral.TOKEN_PROPERTY); |
| doTextReplace(node.getStartPosition(), node.getLength(), newLiteral, group); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(PackageDeclaration node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| if (node.getAST().apiLevel() >= JLS3_INTERNAL) { |
| int pos= rewriteJavadoc(node, PackageDeclaration.JAVADOC_PROPERTY); |
| rewriteModifiers2(node, PackageDeclaration.ANNOTATIONS_PROPERTY, pos); |
| } |
| |
| rewriteRequiredNode(node, PackageDeclaration.NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ParenthesizedExpression node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteRequiredNode(node, ParenthesizedExpression.EXPRESSION_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(PostfixExpression node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int pos= rewriteRequiredNode(node, PostfixExpression.OPERAND_PROPERTY); |
| rewriteOperation(node, PostfixExpression.OPERATOR_PROPERTY, pos); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(PrefixExpression node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteOperation(node, PrefixExpression.OPERATOR_PROPERTY, node.getStartPosition()); |
| rewriteRequiredNode(node, PrefixExpression.OPERAND_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(PrimitiveType node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| if (node.getAST().apiLevel() >= JLS8_INTERNAL) { |
| rewriteTypeAnnotations(node, PrimitiveType.ANNOTATIONS_PROPERTY, node.getStartPosition()); |
| } |
| PrimitiveType.Code newCode= (PrimitiveType.Code) getNewValue(node, PrimitiveType.PRIMITIVE_TYPE_CODE_PROPERTY); |
| TextEditGroup group = getEditGroup(node, PrimitiveType.PRIMITIVE_TYPE_CODE_PROPERTY); |
| doTextReplace(node.getStartPosition(), node.getLength(), newCode.toString(), group); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ProvidesDirective node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos = rewriteRequiredNode(node, ProvidesDirective.NAME_PROPERTY); |
| pos= rewriteNodeList(node, ProvidesDirective.IMPLEMENTATIONS_PROPERTY, pos, " with ", ", "); //$NON-NLS-1$ //$NON-NLS-2$ |
| return false; |
| } |
| |
| @Override |
| public boolean visit(QualifiedName node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteRequiredNode(node, QualifiedName.QUALIFIER_PROPERTY); |
| rewriteRequiredNode(node, QualifiedName.NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SimpleName node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| String newString= (String) getNewValue(node, SimpleName.IDENTIFIER_PROPERTY); |
| TextEditGroup group = getEditGroup(node, SimpleName.IDENTIFIER_PROPERTY); |
| doTextReplace(node.getStartPosition(), node.getLength(), newString, group); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SimpleType node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| if (node.getAST().apiLevel() >= JLS8_INTERNAL) { |
| rewriteTypeAnnotations(node, SimpleType.ANNOTATIONS_PROPERTY, node.getStartPosition()); |
| } |
| rewriteRequiredNode(node, SimpleType.NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SingleVariableDeclaration node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= node.getStartPosition(); |
| int apiLevel= node.getAST().apiLevel(); |
| if (apiLevel == JLS2_INTERNAL) { |
| rewriteModifiers(node, INTERNAL_VARIABLE_MODIFIERS_PROPERTY, pos); |
| } else { |
| rewriteModifiers2(node, SingleVariableDeclaration.MODIFIERS2_PROPERTY, pos); |
| } |
| pos= rewriteRequiredNode(node, SingleVariableDeclaration.TYPE_PROPERTY); |
| if (apiLevel >= JLS3_INTERNAL) { |
| if (isChanged(node, SingleVariableDeclaration.VARARGS_PROPERTY)) { |
| TextEditGroup editGroup = getEditGroup(node, SingleVariableDeclaration.VARARGS_PROPERTY); |
| if (getNewValue(node, SingleVariableDeclaration.VARARGS_PROPERTY).equals(Boolean.TRUE)) { |
| if (apiLevel >= JLS8_INTERNAL) { |
| pos= rewriteVarargsAnnotations(node, SingleVariableDeclaration.VARARGS_ANNOTATIONS_PROPERTY, pos); |
| } |
| int indent= getIndent(node.getStartPosition()); |
| String prefix= this.formatter.VARARGS.getPrefix(indent); |
| doTextInsert(pos, prefix, editGroup); |
| doTextInsert(pos, "...", editGroup); //$NON-NLS-1$ |
| } else { |
| try { |
| int ellipsisEnd; |
| int noOfAnnotations = apiLevel >= JLS8_INTERNAL ? node.varargsAnnotations().size() : 0; |
| if (noOfAnnotations > 0) { |
| Annotation annotation= (Annotation) node.varargsAnnotations().get(noOfAnnotations - 1); |
| int annotationEndPosition= annotation.getStartPosition() + annotation.getLength(); |
| ellipsisEnd= getScanner().getNextEndOffset(annotationEndPosition, true); |
| } else { |
| ellipsisEnd= getScanner().getNextEndOffset(pos, true); |
| } |
| doTextRemove(pos, ellipsisEnd - pos, editGroup); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| } else { |
| if (apiLevel >= JLS8_INTERNAL && node.isVarargs()) { |
| pos = rewriteVarargsAnnotations(node, SingleVariableDeclaration.VARARGS_ANNOTATIONS_PROPERTY, pos); |
| } |
| } |
| if (!node.isVarargs()) { |
| ensureSpaceAfterReplace(node, SingleVariableDeclaration.TYPE_PROPERTY); |
| } |
| } else { |
| ensureSpaceAfterReplace(node, SingleVariableDeclaration.TYPE_PROPERTY); |
| } |
| |
| pos= rewriteRequiredNode(node, SingleVariableDeclaration.NAME_PROPERTY); |
| if (apiLevel < JLS8_INTERNAL) { |
| int extraDims= rewriteExtraDimensions(node, INTERNAL_VARIABLE_EXTRA_DIMENSIONS_PROPERTY, pos); |
| |
| if (extraDims > 0) { |
| int kind= getChangeKind(node, SingleVariableDeclaration.INITIALIZER_PROPERTY); |
| if (kind == RewriteEvent.REMOVED) { |
| try { |
| pos= getScanner().getPreviousTokenEndOffset(TerminalTokens.TokenNameEQUAL, pos); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| pos= node.getStartPosition() + node.getLength(); // insert pos |
| } |
| } |
| } else { |
| pos = rewriteExtraDimensionsInfo(node, pos, SingleVariableDeclaration.EXTRA_DIMENSIONS2_PROPERTY); |
| } |
| |
| rewriteNode(node, SingleVariableDeclaration.INITIALIZER_PROPERTY, pos, this.formatter.VAR_INITIALIZER); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(StringLiteral node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| String escapedSeq= (String) getNewValue(node, StringLiteral.ESCAPED_VALUE_PROPERTY); |
| TextEditGroup group = getEditGroup(node, StringLiteral.ESCAPED_VALUE_PROPERTY); |
| doTextReplace(node.getStartPosition(), node.getLength(), escapedSeq, group); |
| |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SuperConstructorInvocation node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int pos= rewriteOptionalQualifier(node, SuperConstructorInvocation.EXPRESSION_PROPERTY, node.getStartPosition()); |
| |
| if (node.getAST().apiLevel() >= JLS3_INTERNAL) { |
| pos= rewriteOptionalTypeParameters(node, SuperConstructorInvocation.TYPE_ARGUMENTS_PROPERTY, pos, Util.EMPTY_STRING, false, false); |
| } |
| |
| if (isChanged(node, SuperConstructorInvocation.ARGUMENTS_PROPERTY)) { |
| // eval position after opening parent |
| try { |
| pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); |
| rewriteNodeList(node, SuperConstructorInvocation.ARGUMENTS_PROPERTY, pos, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| voidVisit(node, SuperConstructorInvocation.ARGUMENTS_PROPERTY); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SuperFieldAccess node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteOptionalQualifier(node, SuperFieldAccess.QUALIFIER_PROPERTY, node.getStartPosition()); |
| rewriteRequiredNode(node, SuperFieldAccess.NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SuperMethodInvocation node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int pos= rewriteOptionalQualifier(node, SuperMethodInvocation.QUALIFIER_PROPERTY, node.getStartPosition()); |
| |
| if (node.getAST().apiLevel() >= JLS3_INTERNAL) { |
| if (isChanged(node, SuperMethodInvocation.TYPE_ARGUMENTS_PROPERTY)) { |
| try { |
| pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameDOT, pos); |
| rewriteOptionalTypeParameters(node, SuperMethodInvocation.TYPE_ARGUMENTS_PROPERTY, pos, Util.EMPTY_STRING, false, false); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| } |
| |
| pos= rewriteRequiredNode(node, SuperMethodInvocation.NAME_PROPERTY); |
| |
| if (isChanged(node, SuperMethodInvocation.ARGUMENTS_PROPERTY)) { |
| // eval position after opening parent |
| try { |
| pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); |
| rewriteNodeList(node, SuperMethodInvocation.ARGUMENTS_PROPERTY, pos, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| voidVisit(node, SuperMethodInvocation.ARGUMENTS_PROPERTY); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SwitchCase node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| // dont allow switching from case to default or back. New statements should be created. |
| rewriteRequiredNode(node, SwitchCase.EXPRESSION_PROPERTY); |
| return false; |
| } |
| |
| class SwitchListRewriter extends ParagraphListRewriter { |
| |
| private boolean indentSwitchStatementsCompareToCases; |
| |
| public SwitchListRewriter(int initialIndent) { |
| super(initialIndent, 0); |
| this.indentSwitchStatementsCompareToCases = |
| DefaultCodeFormatterConstants.TRUE.equals(ASTRewriteAnalyzer.this.options.get(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_CASES)); |
| } |
| |
| @Override |
| protected int getNodeIndent(int nodeIndex) { |
| int indent= getInitialIndent(); |
| |
| if (this.indentSwitchStatementsCompareToCases) { |
| RewriteEvent event = this.list[nodeIndex]; |
| int changeKind = event.getChangeKind(); |
| |
| ASTNode node; |
| if (changeKind == RewriteEvent.INSERTED || changeKind == RewriteEvent.REPLACED) { |
| node= (ASTNode)event.getNewValue(); |
| } else { |
| node= (ASTNode)event.getOriginalValue(); |
| } |
| |
| if (node.getNodeType() != ASTNode.SWITCH_CASE) { |
| indent++; |
| } |
| } |
| return indent; |
| } |
| |
| @Override |
| protected String getSeparatorString(int nodeIndex) { |
| int total = this.list.length; |
| |
| int nextNodeIndex = nodeIndex + 1; |
| while (nextNodeIndex < total && this.list[nextNodeIndex].getChangeKind() == RewriteEvent.REMOVED) { |
| nextNodeIndex++; |
| } |
| if (nextNodeIndex == total) { |
| return super.getSeparatorString(nodeIndex); |
| } |
| return getSeparatorString(nodeIndex, nextNodeIndex); |
| } |
| |
| @Override |
| protected void updateIndent(int prevMark, int originalOffset, int nodeIndex, TextEditGroup editGroup) { |
| if (prevMark != RewriteEvent.UNCHANGED && prevMark != RewriteEvent.REPLACED) return; |
| |
| // Do not change indent if the previous non removed node is on the same line |
| int previousNonRemovedNodeIndex = nodeIndex - 1; |
| while (previousNonRemovedNodeIndex >= 0 && this.list[previousNonRemovedNodeIndex].getChangeKind() == RewriteEvent.REMOVED) { |
| previousNonRemovedNodeIndex--; |
| } |
| |
| if (previousNonRemovedNodeIndex > -1) { |
| LineInformation lineInformation = getLineInformation(); |
| |
| RewriteEvent prevEvent = this.list[previousNonRemovedNodeIndex]; |
| int prevKind = prevEvent.getChangeKind(); |
| if (prevKind == RewriteEvent.UNCHANGED || prevKind == RewriteEvent.REPLACED) { |
| ASTNode prevNode = (ASTNode) this.list[previousNonRemovedNodeIndex].getOriginalValue(); |
| int prevEndPosition = prevNode.getStartPosition() + prevNode.getLength(); |
| int prevLine = lineInformation.getLineOfOffset(prevEndPosition); |
| int line = lineInformation.getLineOfOffset(originalOffset); |
| |
| if (prevLine == line) { |
| return; |
| } |
| } |
| } |
| |
| int total = this.list.length; |
| while (nodeIndex < total && this.list[nodeIndex].getChangeKind() == RewriteEvent.REMOVED) { |
| nodeIndex++; |
| } |
| |
| int originalIndent = getIndent(originalOffset); |
| int newIndent = getNodeIndent(nodeIndex); |
| |
| if (originalIndent != newIndent) { |
| |
| int line= getLineInformation().getLineOfOffset(originalOffset); |
| if (line >= 0) { |
| int lineStart= getLineInformation().getLineOffset(line); |
| |
| doTextRemove(lineStart, originalOffset - lineStart, editGroup); // remove previous indentation |
| doTextInsert(lineStart, createIndentString(newIndent), editGroup); // add new indentation |
| } |
| } |
| } |
| } |
| |
| @Override |
| public boolean visit(SwitchStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int pos= rewriteRequiredNode(node, SwitchStatement.EXPRESSION_PROPERTY); |
| |
| ChildListPropertyDescriptor property= SwitchStatement.STATEMENTS_PROPERTY; |
| if (getChangeKind(node, property) != RewriteEvent.UNCHANGED) { |
| try { |
| pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLBRACE, pos); |
| int insertIndent= getIndent(node.getStartPosition()); |
| if (DefaultCodeFormatterConstants.TRUE.equals(this.options.get(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH))) { |
| insertIndent++; |
| } |
| |
| ParagraphListRewriter listRewriter= new SwitchListRewriter(insertIndent); |
| StringBuffer leadString= new StringBuffer(); |
| leadString.append(getLineDelimiter()); |
| leadString.append(createIndentString(insertIndent)); |
| listRewriter.rewriteList(node, property, pos, leadString.toString()); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| voidVisit(node, SwitchStatement.STATEMENTS_PROPERTY); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SynchronizedStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteRequiredNode(node, SynchronizedStatement.EXPRESSION_PROPERTY); |
| rewriteRequiredNode(node, SynchronizedStatement.BODY_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ThisExpression node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteOptionalQualifier(node, ThisExpression.QUALIFIER_PROPERTY, node.getStartPosition()); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ThrowStatement node) { |
| try { |
| this.beforeRequiredSpaceIndex = getScanner().getTokenEndOffset(TerminalTokens.TokenNamethrow, node.getStartPosition()); |
| |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| ensureSpaceBeforeReplace(node); |
| |
| rewriteRequiredNode(node, ThrowStatement.EXPRESSION_PROPERTY); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(TryStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= node.getStartPosition(); |
| int level = node.getAST().apiLevel(); |
| if (level >= JLS4_INTERNAL) { |
| StructuralPropertyDescriptor desc = level < JLS9_INTERNAL ? INTERNAL_TRY_STATEMENT_RESOURCES_PROPERTY : TryStatement.RESOURCES2_PROPERTY; |
| if (isChanged(node, desc)) { |
| int indent= getIndent(node.getStartPosition()); |
| String prefix= this.formatter.TRY_RESOURCES.getPrefix(indent); |
| String newParen = this.formatter.TRY_RESOURCES_PAREN.getPrefix(indent) + "("; //$NON-NLS-1$ |
| pos= rewriteNodeList(node, desc, getPosAfterTry(pos), newParen, ")", ";" + prefix); //$NON-NLS-1$ //$NON-NLS-2$ |
| } else { |
| pos= doVisit(node, desc, pos); |
| } |
| } |
| |
| pos= rewriteRequiredNode(node, TryStatement.BODY_PROPERTY); |
| |
| if (isChanged(node, TryStatement.CATCH_CLAUSES_PROPERTY)) { |
| int indent= getIndent(node.getStartPosition()); |
| String prefix= this.formatter.CATCH_BLOCK.getPrefix(indent); |
| pos= rewriteNodeList(node, TryStatement.CATCH_CLAUSES_PROPERTY, pos, prefix, prefix); |
| } else { |
| pos= doVisit(node, TryStatement.CATCH_CLAUSES_PROPERTY, pos); |
| } |
| rewriteNode(node, TryStatement.FINALLY_PROPERTY, pos, this.formatter.FINALLY_BLOCK); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(TypeDeclarationStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| if (node.getAST().apiLevel() == JLS2_INTERNAL) { |
| rewriteRequiredNode(node, INTERNAL_TDS_TYPE_DECLARATION_PROPERTY); |
| } else { |
| rewriteRequiredNode(node, TypeDeclarationStatement.DECLARATION_PROPERTY); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(TypeLiteral node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| rewriteRequiredNode(node, TypeLiteral.TYPE_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(UnionType node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| rewriteNodeList(node, UnionType.TYPES_PROPERTY, node.getStartPosition(), Util.EMPTY_STRING, " | "); //$NON-NLS-1$ |
| return false; |
| } |
| |
| @Override |
| public boolean visit(UsesDirective node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| rewriteRequiredNode(node,UsesDirective.NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(VariableDeclarationExpression node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| // same code as FieldDeclaration |
| int pos= node.getStartPosition(); |
| if (node.getAST().apiLevel() == JLS2_INTERNAL) { |
| rewriteModifiers(node, INTERNAL_VDE_MODIFIERS_PROPERTY, pos); |
| } else { |
| rewriteModifiers2(node, VariableDeclarationExpression.MODIFIERS2_PROPERTY, pos); |
| } |
| pos= rewriteRequiredNode(node, VariableDeclarationExpression.TYPE_PROPERTY); |
| rewriteNodeList(node, VariableDeclarationExpression.FRAGMENTS_PROPERTY, pos, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| return false; |
| } |
| |
| @Override |
| public boolean visit(VariableDeclarationFragment node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int pos= rewriteRequiredNode(node, VariableDeclarationFragment.NAME_PROPERTY); |
| |
| if (node.getAST().apiLevel() < JLS8_INTERNAL) { |
| int extraDims= rewriteExtraDimensions(node, INTERNAL_FRAGMENT_EXTRA_DIMENSIONS_PROPERTY, pos); |
| if (extraDims > 0) { |
| int kind= getChangeKind(node, VariableDeclarationFragment.INITIALIZER_PROPERTY); |
| if (kind == RewriteEvent.REMOVED) { |
| try { |
| pos= getScanner().getPreviousTokenEndOffset(TerminalTokens.TokenNameEQUAL, pos); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| pos= node.getStartPosition() + node.getLength(); // insert pos |
| } |
| } |
| } else { |
| pos = rewriteExtraDimensionsInfo(node, pos, VariableDeclarationFragment.EXTRA_DIMENSIONS2_PROPERTY); |
| } |
| rewriteNode(node, VariableDeclarationFragment.INITIALIZER_PROPERTY, pos, this.formatter.VAR_INITIALIZER); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(VariableDeclarationStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| // same code as FieldDeclaration |
| int pos= node.getStartPosition(); |
| if (node.getAST().apiLevel() == JLS2_INTERNAL) { |
| rewriteModifiers(node, INTERNAL_VDS_MODIFIERS_PROPERTY, pos); |
| } else { |
| rewriteModifiers2(node, VariableDeclarationStatement.MODIFIERS2_PROPERTY, pos); |
| } |
| pos= rewriteRequiredNode(node, VariableDeclarationStatement.TYPE_PROPERTY); |
| |
| rewriteNodeList(node, VariableDeclarationStatement.FRAGMENTS_PROPERTY, pos, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| return false; |
| } |
| |
| @Override |
| public boolean visit(WhileStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int pos= rewriteRequiredNode(node, WhileStatement.EXPRESSION_PROPERTY); |
| |
| try { |
| if (isChanged(node, WhileStatement.BODY_PROPERTY)) { |
| int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRPAREN, pos); |
| rewriteBodyNode(node, WhileStatement.BODY_PROPERTY, startOffset, -1, getIndent(node.getStartPosition()), this.formatter.WHILE_BLOCK); // body |
| } else { |
| voidVisit(node, WhileStatement.BODY_PROPERTY); |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(MemberRef node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| rewriteNode(node, MemberRef.QUALIFIER_PROPERTY, node.getStartPosition(), ASTRewriteFormatter.NONE); |
| |
| rewriteRequiredNode(node, MemberRef.NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(MethodRef node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| rewriteNode(node, MethodRef.QUALIFIER_PROPERTY, node.getStartPosition(), ASTRewriteFormatter.NONE); |
| |
| int pos= rewriteRequiredNode(node, MethodRef.NAME_PROPERTY); |
| |
| if (isChanged(node, MethodRef.PARAMETERS_PROPERTY)) { |
| // eval position after opening parent |
| try { |
| int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); |
| rewriteNodeList(node, MethodRef.PARAMETERS_PROPERTY, startOffset, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| voidVisit(node, MethodRef.PARAMETERS_PROPERTY); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(MethodRefParameter node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteRequiredNode(node, MethodRefParameter.TYPE_PROPERTY); |
| if (node.getAST().apiLevel() >= JLS3_INTERNAL) { |
| if (isChanged(node, MethodRefParameter.VARARGS_PROPERTY)) { |
| if (getNewValue(node, MethodRefParameter.VARARGS_PROPERTY).equals(Boolean.TRUE)) { |
| doTextInsert(pos, "...", getEditGroup(node, MethodRefParameter.VARARGS_PROPERTY)); //$NON-NLS-1$ |
| } else { |
| try { |
| int ellipsisEnd= getScanner().getNextEndOffset(pos, true); |
| doTextRemove(pos, ellipsisEnd - pos, getEditGroup(node, MethodRefParameter.VARARGS_PROPERTY)); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| } |
| } |
| rewriteNode(node, MethodRefParameter.NAME_PROPERTY, pos, ASTRewriteFormatter.SPACE); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(TagElement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| |
| int changeKind= getChangeKind(node, TagElement.TAG_NAME_PROPERTY); |
| switch (changeKind) { |
| case RewriteEvent.INSERTED: { |
| String newTagName= (String) getNewValue(node, TagElement.TAG_NAME_PROPERTY); |
| doTextInsert(node.getStartPosition(), newTagName, getEditGroup(node, TagElement.TAG_NAME_PROPERTY)); |
| break; |
| } |
| case RewriteEvent.REMOVED: { |
| doTextRemove(node.getStartPosition(), findTagNameEnd(node) - node.getStartPosition(), getEditGroup(node, TagElement.TAG_NAME_PROPERTY)); |
| break; |
| } |
| case RewriteEvent.REPLACED: { |
| String newTagName= (String) getNewValue(node, TagElement.TAG_NAME_PROPERTY); |
| doTextReplace(node.getStartPosition(), findTagNameEnd(node) - node.getStartPosition(), newTagName, getEditGroup(node, TagElement.TAG_NAME_PROPERTY)); |
| break; |
| } |
| } |
| |
| if (isChanged(node, TagElement.FRAGMENTS_PROPERTY)) { |
| // eval position after name |
| int endOffset= findTagNameEnd(node); |
| rewriteNodeList(node, TagElement.FRAGMENTS_PROPERTY, endOffset, " ", " "); //$NON-NLS-1$//$NON-NLS-2$ |
| } else { |
| voidVisit(node, TagElement.FRAGMENTS_PROPERTY); |
| } |
| return false; |
| } |
| |
| private int findTagNameEnd(TagElement tagNode) { |
| if (tagNode.getTagName() != null) { |
| char[] cont= getContent(); |
| int len= cont.length; |
| int i= tagNode.getStartPosition(); |
| while (i < len && !IndentManipulation.isIndentChar(cont[i])) { |
| i++; |
| } |
| return i; |
| } |
| return tagNode.getStartPosition(); |
| } |
| |
| @Override |
| public boolean visit(TextElement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| String newText= (String) getNewValue(node, TextElement.TEXT_PROPERTY); |
| TextEditGroup group = getEditGroup(node, TextElement.TEXT_PROPERTY); |
| doTextReplace(node.getStartPosition(), node.getLength(), newText, group); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(AnnotationTypeDeclaration node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteJavadoc(node, AnnotationTypeDeclaration.JAVADOC_PROPERTY); |
| rewriteModifiers2(node, AnnotationTypeDeclaration.MODIFIERS2_PROPERTY, pos); |
| pos= rewriteRequiredNode(node, AnnotationTypeDeclaration.NAME_PROPERTY); |
| |
| int startIndent= getIndent(node.getStartPosition()) + 1; |
| int startPos= getPosAfterLeftBrace(pos); |
| rewriteParagraphList(node, AnnotationTypeDeclaration.BODY_DECLARATIONS_PROPERTY, startPos, startIndent, -1, 2); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(AnnotationTypeMemberDeclaration node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteJavadoc(node, AnnotationTypeMemberDeclaration.JAVADOC_PROPERTY); |
| rewriteModifiers2(node, AnnotationTypeMemberDeclaration.MODIFIERS2_PROPERTY, pos); |
| rewriteRequiredNode(node, AnnotationTypeMemberDeclaration.TYPE_PROPERTY); |
| pos= rewriteRequiredNode(node, AnnotationTypeMemberDeclaration.NAME_PROPERTY); |
| |
| try { |
| int changeKind= getChangeKind(node, AnnotationTypeMemberDeclaration.DEFAULT_PROPERTY); |
| if (changeKind == RewriteEvent.INSERTED || changeKind == RewriteEvent.REMOVED) { |
| pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRPAREN, pos); |
| } |
| rewriteNode(node, AnnotationTypeMemberDeclaration.DEFAULT_PROPERTY, pos, this.formatter.ANNOT_MEMBER_DEFAULT); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(EnhancedForStatement node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| rewriteRequiredNode(node, EnhancedForStatement.PARAMETER_PROPERTY); |
| int pos= rewriteRequiredNode(node, EnhancedForStatement.EXPRESSION_PROPERTY); |
| |
| RewriteEvent bodyEvent= getEvent(node, EnhancedForStatement.BODY_PROPERTY); |
| if (bodyEvent != null && bodyEvent.getChangeKind() == RewriteEvent.REPLACED) { |
| int startOffset; |
| try { |
| startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRPAREN, pos); |
| rewriteBodyNode(node, EnhancedForStatement.BODY_PROPERTY, startOffset, -1, getIndent(node.getStartPosition()), this.formatter.FOR_BLOCK); // body |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| voidVisit(node, EnhancedForStatement.BODY_PROPERTY); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(EnumConstantDeclaration node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteJavadoc(node, EnumConstantDeclaration.JAVADOC_PROPERTY); |
| rewriteModifiers2(node, EnumConstantDeclaration.MODIFIERS2_PROPERTY, pos); |
| pos= rewriteRequiredNode(node, EnumConstantDeclaration.NAME_PROPERTY); |
| RewriteEvent argsEvent= getEvent(node, EnumConstantDeclaration.ARGUMENTS_PROPERTY); |
| if (argsEvent != null && argsEvent.getChangeKind() != RewriteEvent.UNCHANGED) { |
| RewriteEvent[] children= argsEvent.getChildren(); |
| try { |
| int nextTok= getScanner().readNext(pos, true); |
| boolean hasParents= (nextTok == TerminalTokens.TokenNameLPAREN); |
| boolean isAllRemoved= hasParents && isAllOfKind(children, RewriteEvent.REMOVED); |
| String prefix= Util.EMPTY_STRING; |
| if (!hasParents) { |
| prefix= "("; //$NON-NLS-1$ |
| } else if (!isAllRemoved) { |
| pos= getScanner().getCurrentEndOffset(); |
| } |
| pos= rewriteNodeList(node, EnumConstantDeclaration.ARGUMENTS_PROPERTY, pos, prefix, ", "); //$NON-NLS-1$ |
| |
| if (!hasParents) { |
| doTextInsert(pos, ")", getEditGroup(children[children.length - 1])); //$NON-NLS-1$ |
| } else if (isAllRemoved) { |
| int afterClosing= getScanner().getNextEndOffset(pos, true); |
| doTextRemove(pos, afterClosing - pos, getEditGroup(children[children.length - 1])); |
| pos= afterClosing; |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| pos= doVisit(node, EnumConstantDeclaration.ARGUMENTS_PROPERTY, pos); |
| } |
| |
| if (isChanged(node, EnumConstantDeclaration.ANONYMOUS_CLASS_DECLARATION_PROPERTY)) { |
| int kind= getChangeKind(node, EnumConstantDeclaration.ANONYMOUS_CLASS_DECLARATION_PROPERTY); |
| if (kind == RewriteEvent.REMOVED) { |
| try { |
| // 'pos' can be before brace |
| pos= getScanner().getPreviousTokenEndOffset(TerminalTokens.TokenNameLBRACE, pos); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| pos= node.getStartPosition() + node.getLength(); // insert pos |
| } |
| rewriteNode(node, EnumConstantDeclaration.ANONYMOUS_CLASS_DECLARATION_PROPERTY, pos, ASTRewriteFormatter.SPACE); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(EnumDeclaration node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteJavadoc(node, EnumDeclaration.JAVADOC_PROPERTY); |
| rewriteModifiers2(node, EnumDeclaration.MODIFIERS2_PROPERTY, pos); |
| pos= rewriteRequiredNode(node, EnumDeclaration.NAME_PROPERTY); |
| pos= rewriteNodeList(node, EnumDeclaration.SUPER_INTERFACE_TYPES_PROPERTY, pos, " implements ", ", "); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| pos= getPosAfterLeftBrace(pos); |
| |
| String leadString= Util.EMPTY_STRING; |
| RewriteEvent constEvent= getEvent(node, EnumDeclaration.ENUM_CONSTANTS_PROPERTY); |
| |
| if (constEvent != null && constEvent.getChangeKind() != RewriteEvent.UNCHANGED) { |
| RewriteEvent[] events= constEvent.getChildren(); |
| if (isAllOfKind(events, RewriteEvent.INSERTED)) { |
| leadString= this.formatter.FIRST_ENUM_CONST.getPrefix(getIndent(node.getStartPosition())); |
| } |
| } |
| pos= rewriteNodeList(node, EnumDeclaration.ENUM_CONSTANTS_PROPERTY, pos, leadString, ", "); //$NON-NLS-1$ |
| |
| RewriteEvent bodyEvent= getEvent(node, EnumDeclaration.BODY_DECLARATIONS_PROPERTY); |
| int indent= 0; |
| if (bodyEvent != null && bodyEvent.getChangeKind() != RewriteEvent.UNCHANGED) { |
| boolean hasConstants= !((List) getNewValue(node, EnumDeclaration.ENUM_CONSTANTS_PROPERTY)).isEmpty(); |
| |
| RewriteEvent[] children= bodyEvent.getChildren(); |
| try { |
| if (hasConstants) { |
| indent= getIndent(pos); |
| } else { |
| indent= getIndent(node.getStartPosition()) + 1; |
| } |
| int token= getScanner().readNext(pos, true); |
| boolean hasSemicolon= token == TerminalTokens.TokenNameSEMICOLON; |
| if (!hasSemicolon && isAllOfKind(children, RewriteEvent.INSERTED)) { |
| if (!hasConstants) { |
| String str= this.formatter.FIRST_ENUM_CONST.getPrefix(indent - 1); |
| doTextInsert(pos, str, getEditGroup(children[0])); |
| } |
| if (token == TerminalTokens.TokenNameCOMMA) { |
| // a comma is at the end of the enum constant before a potential semicolon |
| int endPos= getScanner().getCurrentEndOffset(); |
| int nextToken= getScanner().readNext(endPos, true); |
| if (nextToken != TerminalTokens.TokenNameSEMICOLON) { |
| doTextInsert(endPos, ";", getEditGroup(children[0])); //$NON-NLS-1$ |
| } else { |
| endPos= getScanner().getCurrentEndOffset(); |
| if (isAllOfKind(children, RewriteEvent.REMOVED)) { |
| doTextRemove(pos, endPos - pos, getEditGroup(children[0])); |
| } |
| } |
| pos= endPos; |
| } else { |
| doTextInsert(pos, ";", getEditGroup(children[0])); //$NON-NLS-1$ |
| } |
| } else if (hasSemicolon) { |
| int endPos= getScanner().getCurrentEndOffset(); |
| if (isAllOfKind(children, RewriteEvent.REMOVED)) { |
| doTextRemove(pos, endPos - pos, getEditGroup(children[0])); |
| } |
| pos= endPos; |
| } |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| rewriteParagraphList(node, EnumDeclaration.BODY_DECLARATIONS_PROPERTY, pos, indent, -1, 2); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ExpressionMethodReference node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteRequiredNode(node, ExpressionMethodReference.EXPRESSION_PROPERTY); |
| visitReferenceTypeArguments(node, ExpressionMethodReference.TYPE_ARGUMENTS_PROPERTY, pos); |
| rewriteRequiredNode(node, ExpressionMethodReference.NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(MarkerAnnotation node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| rewriteRequiredNode(node, MarkerAnnotation.TYPE_NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(MemberValuePair node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| rewriteRequiredNode(node, MemberValuePair.NAME_PROPERTY); |
| rewriteRequiredNode(node, MemberValuePair.VALUE_PROPERTY); |
| |
| return false; |
| } |
| |
| @Override |
| public boolean visit(Modifier node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| String newText= getNewValue(node, Modifier.KEYWORD_PROPERTY).toString(); // type Modifier.ModifierKeyword |
| TextEditGroup group = getEditGroup(node, Modifier.KEYWORD_PROPERTY); |
| doTextReplace(node.getStartPosition(), node.getLength(), newText, group); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ModuleModifier node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| String newText= getNewValue(node, ModuleModifier.KEYWORD_PROPERTY).toString(); // type ModuleModifier.ModuleModifierKeyword |
| TextEditGroup group = getEditGroup(node, ModuleModifier.KEYWORD_PROPERTY); |
| doTextReplace(node.getStartPosition(), node.getLength(), newText, group); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(NormalAnnotation node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteRequiredNode(node, NormalAnnotation.TYPE_NAME_PROPERTY); |
| if (isChanged(node, NormalAnnotation.VALUES_PROPERTY)) { |
| // eval position after opening parent |
| try { |
| int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); |
| rewriteNodeList(node, NormalAnnotation.VALUES_PROPERTY, startOffset, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| voidVisit(node, NormalAnnotation.VALUES_PROPERTY); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(NameQualifiedType node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos = rewriteRequiredNode(node, NameQualifiedType.QUALIFIER_PROPERTY); |
| try { |
| pos = getScanner().getTokenEndOffset(TerminalTokens.TokenNameDOT, pos); |
| rewriteTypeAnnotations(node, NameQualifiedType.ANNOTATIONS_PROPERTY, pos); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| rewriteRequiredNode(node, NameQualifiedType.NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(ParameterizedType node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteRequiredNode(node, ParameterizedType.TYPE_PROPERTY); |
| if (isChanged(node, ParameterizedType.TYPE_ARGUMENTS_PROPERTY)) { |
| // eval position after opening parent |
| try { |
| int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLESS, pos); |
| rewriteNodeList(node, ParameterizedType.TYPE_ARGUMENTS_PROPERTY, startOffset, Util.EMPTY_STRING, ", "); //$NON-NLS-1$ |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } else { |
| voidVisit(node, ParameterizedType.TYPE_ARGUMENTS_PROPERTY); |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean visit(QualifiedType node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos = rewriteRequiredNode(node, QualifiedType.QUALIFIER_PROPERTY); |
| if (node.getAST().apiLevel() >= JLS8_INTERNAL) { |
| try { |
| pos = getScanner().getTokenEndOffset(TerminalTokens.TokenNameDOT, pos); |
| rewriteTypeAnnotations(node, QualifiedType.ANNOTATIONS_PROPERTY, pos); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| } |
| rewriteRequiredNode(node, QualifiedType.NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SingleMemberAnnotation node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| rewriteRequiredNode(node, SingleMemberAnnotation.TYPE_NAME_PROPERTY); |
| rewriteRequiredNode(node, SingleMemberAnnotation.VALUE_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SuperMethodReference node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos = rewriteOptionalQualifier(node, SuperMethodReference.QUALIFIER_PROPERTY, node.getStartPosition()); |
| visitReferenceTypeArguments(node, SuperMethodReference.TYPE_ARGUMENTS_PROPERTY, pos); |
| rewriteRequiredNode(node, SuperMethodReference.NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(TypeMethodReference node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos= rewriteRequiredNode(node, TypeMethodReference.TYPE_PROPERTY); |
| visitReferenceTypeArguments(node, TypeMethodReference.TYPE_ARGUMENTS_PROPERTY, pos); |
| rewriteRequiredNode(node, TypeMethodReference.NAME_PROPERTY); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(TypeParameter node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| int pos; |
| if (node.getAST().apiLevel() >= JLS8_INTERNAL) { |
| pos = rewriteModifiers2(node, TypeParameter.MODIFIERS_PROPERTY, node.getStartPosition()); |
| } |
| pos= rewriteRequiredNode(node, TypeParameter.NAME_PROPERTY); |
| rewriteNodeList(node, TypeParameter.TYPE_BOUNDS_PROPERTY, pos, " extends ", " & "); //$NON-NLS-1$ //$NON-NLS-2$ |
| return false; |
| } |
| |
| @Override |
| public boolean visit(WildcardType node) { |
| if (!hasChildrenChanges(node)) { |
| return doVisitUnchangedChildren(node); |
| } |
| if (node.getAST().apiLevel() >= JLS8_INTERNAL) { |
| rewriteTypeAnnotations(node, WildcardType.ANNOTATIONS_PROPERTY, node.getStartPosition()); |
| } |
| try { |
| int pos= getScanner().getNextEndOffset(node.getStartPosition(), true); // pos after question mark |
| |
| Prefix prefix; |
| if (Boolean.TRUE.equals(getNewValue(node, WildcardType.UPPER_BOUND_PROPERTY))) { |
| prefix= this.formatter.WILDCARD_EXTENDS; |
| } else { |
| prefix= this.formatter.WILDCARD_SUPER; |
| } |
| |
| int boundKindChange= getChangeKind(node, WildcardType.UPPER_BOUND_PROPERTY); |
| if (boundKindChange != RewriteEvent.UNCHANGED) { |
| int boundTypeChange= getChangeKind(node, WildcardType.BOUND_PROPERTY); |
| if (boundTypeChange != RewriteEvent.INSERTED && boundTypeChange != RewriteEvent.REMOVED) { |
| ASTNode type= (ASTNode) getOriginalValue(node, WildcardType.BOUND_PROPERTY); |
| String str= prefix.getPrefix(0); |
| doTextReplace(pos, type.getStartPosition() - pos, str, getEditGroup(node, WildcardType.BOUND_PROPERTY)); |
| } |
| } |
| rewriteNode(node, WildcardType.BOUND_PROPERTY, pos, prefix); |
| } catch (CoreException e) { |
| handleException(e); |
| } |
| return false; |
| } |
| |
| final void handleException(Throwable e) { |
| throw new IllegalArgumentException("Document does not match the AST", e); //$NON-NLS-1$ |
| } |
| |
| } |