/******************************************************************************* * Copyright (c) 2000, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.wst.jsdt.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.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; import org.eclipse.wst.jsdt.core.ToolFactory; import org.eclipse.wst.jsdt.core.compiler.IScanner; import org.eclipse.wst.jsdt.core.compiler.ITerminalSymbols; import org.eclipse.wst.jsdt.core.dom.AST; import org.eclipse.wst.jsdt.core.dom.ASTNode; import org.eclipse.wst.jsdt.core.dom.ASTVisitor; import org.eclipse.wst.jsdt.core.dom.AnonymousClassDeclaration; import org.eclipse.wst.jsdt.core.dom.ArrayAccess; import org.eclipse.wst.jsdt.core.dom.ArrayCreation; import org.eclipse.wst.jsdt.core.dom.ArrayInitializer; import org.eclipse.wst.jsdt.core.dom.ArrayType; import org.eclipse.wst.jsdt.core.dom.Assignment; import org.eclipse.wst.jsdt.core.dom.Block; import org.eclipse.wst.jsdt.core.dom.BooleanLiteral; import org.eclipse.wst.jsdt.core.dom.BreakStatement; import org.eclipse.wst.jsdt.core.dom.CatchClause; import org.eclipse.wst.jsdt.core.dom.CharacterLiteral; import org.eclipse.wst.jsdt.core.dom.ChildListPropertyDescriptor; import org.eclipse.wst.jsdt.core.dom.ChildPropertyDescriptor; import org.eclipse.wst.jsdt.core.dom.ClassInstanceCreation; import org.eclipse.wst.jsdt.core.dom.ConditionalExpression; import org.eclipse.wst.jsdt.core.dom.ConstructorInvocation; import org.eclipse.wst.jsdt.core.dom.ContinueStatement; import org.eclipse.wst.jsdt.core.dom.DoStatement; import org.eclipse.wst.jsdt.core.dom.EmptyStatement; import org.eclipse.wst.jsdt.core.dom.EnhancedForStatement; import org.eclipse.wst.jsdt.core.dom.ExpressionStatement; import org.eclipse.wst.jsdt.core.dom.FieldAccess; import org.eclipse.wst.jsdt.core.dom.FieldDeclaration; import org.eclipse.wst.jsdt.core.dom.ForInStatement; import org.eclipse.wst.jsdt.core.dom.ForStatement; import org.eclipse.wst.jsdt.core.dom.FunctionDeclaration; import org.eclipse.wst.jsdt.core.dom.FunctionExpression; import org.eclipse.wst.jsdt.core.dom.FunctionInvocation; import org.eclipse.wst.jsdt.core.dom.FunctionRef; import org.eclipse.wst.jsdt.core.dom.FunctionRefParameter; import org.eclipse.wst.jsdt.core.dom.IfStatement; import org.eclipse.wst.jsdt.core.dom.ImportDeclaration; import org.eclipse.wst.jsdt.core.dom.InfixExpression; import org.eclipse.wst.jsdt.core.dom.Initializer; import org.eclipse.wst.jsdt.core.dom.InstanceofExpression; import org.eclipse.wst.jsdt.core.dom.JSdoc; import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit; import org.eclipse.wst.jsdt.core.dom.LabeledStatement; import org.eclipse.wst.jsdt.core.dom.ListExpression; import org.eclipse.wst.jsdt.core.dom.MemberRef; import org.eclipse.wst.jsdt.core.dom.Modifier; import org.eclipse.wst.jsdt.core.dom.NullLiteral; import org.eclipse.wst.jsdt.core.dom.NumberLiteral; import org.eclipse.wst.jsdt.core.dom.ObjectLiteral; import org.eclipse.wst.jsdt.core.dom.ObjectLiteralField; import org.eclipse.wst.jsdt.core.dom.PackageDeclaration; import org.eclipse.wst.jsdt.core.dom.ParenthesizedExpression; import org.eclipse.wst.jsdt.core.dom.PostfixExpression; import org.eclipse.wst.jsdt.core.dom.PrefixExpression; import org.eclipse.wst.jsdt.core.dom.PrimitiveType; import org.eclipse.wst.jsdt.core.dom.QualifiedName; import org.eclipse.wst.jsdt.core.dom.QualifiedType; import org.eclipse.wst.jsdt.core.dom.RegularExpressionLiteral; import org.eclipse.wst.jsdt.core.dom.ReturnStatement; import org.eclipse.wst.jsdt.core.dom.SimpleName; import org.eclipse.wst.jsdt.core.dom.SimpleType; import org.eclipse.wst.jsdt.core.dom.SingleVariableDeclaration; import org.eclipse.wst.jsdt.core.dom.StringLiteral; import org.eclipse.wst.jsdt.core.dom.StructuralPropertyDescriptor; import org.eclipse.wst.jsdt.core.dom.SuperConstructorInvocation; import org.eclipse.wst.jsdt.core.dom.SuperFieldAccess; import org.eclipse.wst.jsdt.core.dom.SuperMethodInvocation; import org.eclipse.wst.jsdt.core.dom.SwitchCase; import org.eclipse.wst.jsdt.core.dom.SwitchStatement; import org.eclipse.wst.jsdt.core.dom.TagElement; import org.eclipse.wst.jsdt.core.dom.TextElement; import org.eclipse.wst.jsdt.core.dom.ThisExpression; import org.eclipse.wst.jsdt.core.dom.ThrowStatement; import org.eclipse.wst.jsdt.core.dom.TryStatement; import org.eclipse.wst.jsdt.core.dom.Type; import org.eclipse.wst.jsdt.core.dom.TypeDeclaration; import org.eclipse.wst.jsdt.core.dom.TypeDeclarationStatement; import org.eclipse.wst.jsdt.core.dom.TypeLiteral; import org.eclipse.wst.jsdt.core.dom.UndefinedLiteral; import org.eclipse.wst.jsdt.core.dom.VariableDeclarationExpression; import org.eclipse.wst.jsdt.core.dom.VariableDeclarationFragment; import org.eclipse.wst.jsdt.core.dom.VariableDeclarationStatement; import org.eclipse.wst.jsdt.core.dom.WhileStatement; import org.eclipse.wst.jsdt.core.dom.WithStatement; import org.eclipse.wst.jsdt.core.dom.rewrite.TargetSourceRangeComputer; import org.eclipse.wst.jsdt.core.dom.rewrite.TargetSourceRangeComputer.SourceRange; import org.eclipse.wst.jsdt.core.formatter.IndentManipulation; import org.eclipse.wst.jsdt.internal.compiler.parser.ScannerHelper; import org.eclipse.wst.jsdt.internal.core.dom.rewrite.ASTRewriteFormatter.BlockContext; import org.eclipse.wst.jsdt.internal.core.dom.rewrite.ASTRewriteFormatter.NodeMarker; import org.eclipse.wst.jsdt.internal.core.dom.rewrite.ASTRewriteFormatter.Prefix; import org.eclipse.wst.jsdt.internal.core.dom.rewrite.NodeInfoStore.CopyPlaceholderData; import org.eclipse.wst.jsdt.internal.core.dom.rewrite.NodeInfoStore.StringPlaceholderData; import org.eclipse.wst.jsdt.internal.core.dom.rewrite.RewriteEventStore.CopySourceInfo; /** * 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. */ public final class ASTRewriteAnalyzer extends ASTVisitor { /** * Internal synonym for deprecated constant AST.JLS2 * to alleviate deprecated warnings. * @deprecated */ /*package*/ static final int JLS2_INTERNAL = AST.JLS2; 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; /** * Constructor for ASTRewriteAnalyzer. * @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) or <code>null</code>. * @param extendedSourceRangeComputer the source range computer to use */ public ASTRewriteAnalyzer(char[] content, LineInformation lineInfo, String lineDelim, TextEdit rootEdit, RewriteEventStore eventStore, NodeInfoStore nodeInfos, List comments, Map options, TargetSourceRangeComputer extendedSourceRangeComputer) { 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); } final TokenScanner getScanner() { if (this.tokenScanner == null) { IScanner scanner= ToolFactory.createScanner(true, false, false, false); scanner.setSource(this.content); this.tokenScanner= new TokenScanner(scanner); } return this.tokenScanner; } final char[] getContent() { return this.content; } final LineInformation getLineInformation() { return this.lineInfo; } /** * 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(content[i])) { i++; } return new String(cont, lineStart, i - lineStart); } return new 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 contantSeparator; 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.contantSeparator; } 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.contantSeparator= separator; return rewriteList(parent, property, offset, keyword); } private boolean insertAfterSeparator(ASTNode node) { return !isInsertBoundToPrevious(node); } public final int rewriteList(ASTNode parent, StructuralPropertyDescriptor property, int offset, String keyword) { 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; } } if (currPos == -1) { // 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; 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)) { 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); } } else if (currMark == RewriteEvent.REMOVED) { ASTNode node= (ASTNode) currEvent.getOriginalValue(); TextEditGroup editGroup= getEditGroup(currEvent); int currEnd= getEndOfNode(node); 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 currPos= currEnd; prevEnd= currEnd; } else { // remove element and next separator int end= getStartOfNextNode(nextIndex, currEnd); // start of next doTextRemoveAndVisit(currPos, currEnd - currPos, node, getEditGroup(currEvent)); // remove node 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(); 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; } } } return currPos; } } 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); int nodeEnd= getExtendedEnd(node); // if there is a prefix, remove the prefix as well int 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(); if (endPos == -1) { endPos= getExtendedEnd(node); } 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]; doTextInsert(offset, prefix, editGroup); String lineInPrefix= getCurrentLine(prefix, prefix.length()); if (prefix.length() != lineInPrefix.length()) { // prefix contains a new line: update the indent to the one used in the prefix indent= this.formatter.computeIndentUnits(lineInPrefix); } 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(ITerminalSymbols.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(ITerminalSymbols.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(ITerminalSymbols.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; } protected int getInitialIndent() { return this.initialIndent; } protected String getSeparatorString(int nodeIndex) { 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(nodeIndex + 1))); 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; } } 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(ITerminalSymbols.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(ITerminalSymbols.TokenNameGREATER, pos); // set pos to '>' endPos= getScanner().getNextStartOffset(endPos, false); String replacement= needsSpaceOnRemoveAll ? String.valueOf(' ') : new 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(ITerminalSymbols.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 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(FunctionDeclaration parent, int startPos) { RewriteEvent event= getEvent(parent, FunctionDeclaration.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, FunctionDeclaration.BODY_PROPERTY); } 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(ITerminalSymbols.TokenNameRBRACKET); } doTextRemove(pos, getScanner().getCurrentEndOffset() - pos, editGroup); } catch (CoreException e) { handleException(e); } } } /* * 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 { int nextToken= getScanner().readNext(pos, true); if (nextToken == ITerminalSymbols.TokenNameLBRACE) { 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 } 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 { String destIndentString= this.formatter.getIndentString(getCurrentLine(formatted, 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 String getCurrentLine(String str, int pos) { for (int i= pos - 1; i>= 0; i--) { char ch= str.charAt(i); if (IndentManipulation.isLineDelimiterChar(ch)) { return str.substring(i + 1, pos); } } return str.substring(0, pos); } 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 ITerminalSymbols.TokenNamepublic: keep= Modifier.isPublic(newModifiers); break; // case ITerminalSymbols.TokenNameprotected: keep= Modifier.isProtected(newModifiers); break; // case ITerminalSymbols.TokenNameprivate: keep= Modifier.isPrivate(newModifiers); break; // case ITerminalSymbols.TokenNamestatic: keep= Modifier.isStatic(newModifiers); break; // case ITerminalSymbols.TokenNamefinal: keep= Modifier.isFinal(newModifiers); break; // case ITerminalSymbols.TokenNameabstract: keep= Modifier.isAbstract(newModifiers); break; // case ITerminalSymbols.TokenNamenative: keep= Modifier.isNative(newModifiers); break; // case ITerminalSymbols.TokenNamevolatile: keep= Modifier.isVolatile(newModifiers); break; // case ITerminalSymbols.TokenNamestrictfp: keep= Modifier.isStrictfp(newModifiers); break; // case ITerminalSymbols.TokenNametransient: keep= Modifier.isTransient(newModifiers); break; // case ITerminalSymbols.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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.ListRewriter#getSeparatorString(int) */ protected String getSeparatorString(int nodeIndex) { ASTNode curr= getNewNode(nodeIndex); 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); // if (isAllInsert || isAllRemove) { // // update pos // try { // pos= getScanner().getNextStartOffset(pos, false); // } catch (CoreException e) { // handleException(e); // } // } // // int endPos= new ModifierRewriter(this.formatter.ANNOTATION_SEPARATION).rewriteList(node, property, pos, "", " "); //$NON-NLS-1$ //$NON-NLS-2$ // // try { // int nextPos= getScanner().getNextStartOffset(endPos, false); // // boolean lastUnchanged= children[children.length - 1].getChangeKind() != RewriteEvent.UNCHANGED; // // if (isAllRemove) { // doTextRemove(endPos, nextPos - endPos, getEditGroup(children[children.length - 1])); // return nextPos; // } else if (isAllInsert || (nextPos == endPos && lastUnchanged)) { // see bug 165654 // RewriteEvent lastChild= children[children.length - 1]; // String separator; // if (lastChild.getNewValue() instanceof Annotation) { // separator= this.formatter.ANNOTATION_SEPARATION.getPrefix(getIndent(pos)); // } else { // separator= String.valueOf(' '); // } // doTextInsert(endPos, separator, getEditGroup(lastChild)); // } // } catch (CoreException e) { // handleException(e); // } // return endPos; } 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); } } } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#postVisit(ASTNode) */ 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); } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#preVisit(ASTNode) */ 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; } } 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(); } } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(JavaScriptUnit) */ public boolean visit(JavaScriptUnit node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int startPos= rewriteNode(node, JavaScriptUnit.PACKAGE_PROPERTY, 0, ASTRewriteFormatter.NONE); if (getChangeKind(node, JavaScriptUnit.PACKAGE_PROPERTY) == RewriteEvent.INSERTED) { doTextInsert(0, getLineDelimiter(), getEditGroup(node, JavaScriptUnit.PACKAGE_PROPERTY)); } startPos= rewriteParagraphList(node, JavaScriptUnit.IMPORTS_PROPERTY, startPos, 0, 0, 2); // startPos= rewriteParagraphList(node, JavaScriptUnit.TYPES_PROPERTY, startPos, 0, -1, 2); rewriteParagraphList(node, JavaScriptUnit.STATEMENTS_PROPERTY, startPos, 0, -1, 1); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(TypeDeclaration) */ public boolean visit(TypeDeclaration node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int apiLevel= node.getAST().apiLevel(); int pos= rewriteJavadoc(node, TypeDeclaration.JAVADOC_PROPERTY); if (apiLevel == JLS2_INTERNAL) { rewriteModifiers(node, TypeDeclaration.MODIFIERS_PROPERTY, pos); } else { rewriteModifiers2(node, TypeDeclaration.MODIFIERS2_PROPERTY, pos); } // name pos= rewriteRequiredNode(node, TypeDeclaration.NAME_PROPERTY); // superclass ChildPropertyDescriptor superClassProperty= (apiLevel == JLS2_INTERNAL) ? TypeDeclaration.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); } } // 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(FunctionDeclaration node, boolean isConstructor, boolean isConstructorChange) { ChildPropertyDescriptor property= (node.getAST().apiLevel() == JLS2_INTERNAL) ? FunctionDeclaration.RETURN_TYPE_PROPERTY : FunctionDeclaration.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); 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, FunctionDeclaration.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); } } } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(FunctionDeclaration) */ public boolean visit(FunctionDeclaration node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int pos= rewriteJavadoc(node, FunctionDeclaration.JAVADOC_PROPERTY); // if (node.getAST().apiLevel() == JLS2_INTERNAL) { // rewriteModifiers(node, FunctionDeclaration.MODIFIERS_PROPERTY, pos); // } else { // pos= rewriteModifiers2(node, FunctionDeclaration.MODIFIERS2_PROPERTY, pos); // pos= rewriteOptionalTypeParameters(node, FunctionDeclaration.TYPE_PARAMETERS_PROPERTY, pos, " ", true, pos != node.getStartPosition()); //$NON-NLS-1$ // } boolean isConstructorChange= isChanged(node, FunctionDeclaration.CONSTRUCTOR_PROPERTY); boolean isConstructor= ((Boolean) getOriginalValue(node, FunctionDeclaration.CONSTRUCTOR_PROPERTY)).booleanValue(); if (!isConstructor || isConstructorChange) { rewriteReturnType(node, isConstructor, isConstructorChange); } try { // method name pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNamefunction, pos); pos= rewriteNode(node, FunctionDeclaration.NAME_PROPERTY, pos, ASTRewriteFormatter.NONE); // parameters if (isChanged(node, FunctionDeclaration.PARAMETERS_PROPERTY)) { pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameLPAREN, pos); pos= rewriteNodeList(node, FunctionDeclaration.PARAMETERS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ } else { pos= doVisit(node, FunctionDeclaration.PARAMETERS_PROPERTY, pos); } pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameRPAREN, pos); int extraDims= rewriteExtraDimensions(node, FunctionDeclaration.EXTRA_DIMENSIONS_PROPERTY, pos); boolean hasExceptionChanges= isChanged(node, FunctionDeclaration.THROWN_EXCEPTIONS_PROPERTY); int bodyChangeKind= getChangeKind(node, FunctionDeclaration.BODY_PROPERTY); if ((extraDims > 0) && (hasExceptionChanges || bodyChangeKind == RewriteEvent.INSERTED || bodyChangeKind == RewriteEvent.REMOVED)) { int dim= ((Integer) getOriginalValue(node, FunctionDeclaration.EXTRA_DIMENSIONS_PROPERTY)).intValue(); while (dim > 0) { pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameRBRACKET, pos); dim--; } } pos= rewriteNodeList(node, FunctionDeclaration.THROWN_EXCEPTIONS_PROPERTY, pos, " throws ", ", "); //$NON-NLS-1$ //$NON-NLS-2$ rewriteMethodBody(node, pos); } catch (CoreException e) { // ignore } return false; } /* (non-Javadoc) * @see org.eclipse.jsdt.core.dom.ASTVisitor#visit(CastExpression) */ public boolean visit(FunctionExpression node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteRequiredNode(node, FunctionExpression.METHOD_PROPERTY); return false; } /* (non-Javadoc) * @see org.eclipse.jsdt.core.dom.ASTVisitor#visit(CastExpression) */ public boolean visit(ObjectLiteralField node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteRequiredNode(node, ObjectLiteralField.FIELD_NAME_PROPERTY); rewriteRequiredNode(node, ObjectLiteralField.INITIALIZER_PROPERTY); return false; } public boolean visit(RegularExpressionLiteral node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } String escapedSeq= (String) getNewValue(node, RegularExpressionLiteral.REGULAR_EXPRESSION_PROPERTY); TextEditGroup group = getEditGroup(node, RegularExpressionLiteral.REGULAR_EXPRESSION_PROPERTY); doTextReplace(node.getStartPosition(), node.getLength(), escapedSeq, group); return false; } public boolean visit(ObjectLiteral node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int pos= node.getStartPosition(); try { if (isChanged(node, ObjectLiteral.FIELDS_PROPERTY)) { pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameLBRACE, pos); pos= rewriteNodeList(node, ObjectLiteral.FIELDS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ } else { pos= doVisit(node, ObjectLiteral.FIELDS_PROPERTY, pos); } } catch (CoreException e) { handleException(e); } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(Block) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ReturnStatement) */ public boolean visit(ReturnStatement node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } try { int offset= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNamereturn, node.getStartPosition()); ensureSpaceBeforeReplace(node, ReturnStatement.EXPRESSION_PROPERTY, offset, 0); rewriteNode(node, ReturnStatement.EXPRESSION_PROPERTY, offset, ASTRewriteFormatter.SPACE); } catch (CoreException e) { handleException(e); } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(AnonymousClassDeclaration) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ArrayAccess) */ public boolean visit(ArrayAccess node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteRequiredNode(node, ArrayAccess.ARRAY_PROPERTY); rewriteRequiredNode(node, ArrayAccess.INDEX_PROPERTY); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ArrayCreation) */ public boolean visit(ArrayCreation node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } ArrayType arrayType= (ArrayType) getOriginalValue(node, ArrayCreation.TYPE_PROPERTY); int nOldBrackets= getDimensions(arrayType); // number of total brackets int nNewBrackets= nOldBrackets; 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 ArrayType 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); } nNewBrackets= replacingType.getDimensions(); // is replaced type } voidVisit(arrayType); try { int offset= getScanner().getTokenStartOffset(ITerminalSymbols.TokenNameLBRACKET, arrayType.getStartPosition()); // dimension node with expressions RewriteEvent dimEvent= getEvent(node, ArrayCreation.DIMENSIONS_PROPERTY); boolean hasDimensionChanges= (dimEvent != null && dimEvent.getChangeKind() != RewriteEvent.UNCHANGED); if (hasDimensionChanges) { RewriteEvent[] events= dimEvent.getChildren(); // offset on first opening brace for (int i= 0; i < events.length; i++) { RewriteEvent event= events[i]; int changeKind= event.getChangeKind(); if (changeKind == RewriteEvent.INSERTED) { // insert new dimension editGroup= getEditGroup(event); doTextInsert(offset, "[", editGroup); //$NON-NLS-1$ doTextInsert(offset, (ASTNode) event.getNewValue(), 0, false, editGroup); doTextInsert(offset, "]", editGroup); //$NON-NLS-1$ nNewBrackets--; } else { ASTNode elem= (ASTNode) event.getOriginalValue(); int elemEnd= elem.getStartPosition() + elem.getLength(); int endPos= getScanner().getTokenEndOffset(ITerminalSymbols.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); nNewBrackets--; } else { voidVisit(elem); nNewBrackets--; } offset= endPos; nOldBrackets--; } } } else { offset= doVisit(node, ArrayCreation.DIMENSIONS_PROPERTY, offset); } if (nOldBrackets != nNewBrackets) { if (!hasDimensionChanges) { offset= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameRBRACKET, offset); } rewriteExtraDimensions(nOldBrackets, nNewBrackets, offset, editGroup); } int kind= getChangeKind(node, ArrayCreation.INITIALIZER_PROPERTY); if (kind == RewriteEvent.REMOVED) { offset= getScanner().getPreviousTokenEndOffset(ITerminalSymbols.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 Type getElementType(ArrayType parent) { Type t = (Type) getOriginalValue(parent, ArrayType.COMPONENT_TYPE_PROPERTY); while (t.isArrayType()) { t = (Type) getOriginalValue(t, ArrayType.COMPONENT_TYPE_PROPERTY); } return t; } private int getDimensions(ArrayType parent) { Type t = (Type) getOriginalValue(parent, ArrayType.COMPONENT_TYPE_PROPERTY); int dimensions = 1; // always include this array type while (t.isArrayType()) { dimensions++; t = (Type) getOriginalValue(t, ArrayType.COMPONENT_TYPE_PROPERTY); } return dimensions; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ArrayInitializer) */ public boolean visit(ArrayInitializer node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int startPos= getPosAfterLeftBrace(node.getStartPosition()); rewriteNodeList(node, ArrayInitializer.EXPRESSIONS_PROPERTY, startPos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ArrayType) */ public boolean visit(ArrayType node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteRequiredNode(node, ArrayType.COMPONENT_TYPE_PROPERTY); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(Assignment) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(BooleanLiteral) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(BreakStatement) */ public boolean visit(BreakStatement node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } try { int offset= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNamebreak, node.getStartPosition()); rewriteNode(node, BreakStatement.LABEL_PROPERTY, offset, ASTRewriteFormatter.SPACE); // space between break and label } catch (CoreException e) { handleException(e); } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(CatchClause) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(CharacterLiteral) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ClassInstanceCreation) */ public boolean visit(ClassInstanceCreation node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int pos= rewriteOptionalQualifier(node, ClassInstanceCreation.EXPRESSION_PROPERTY, node.getStartPosition()); pos= rewriteRequiredNode(node, ClassInstanceCreation.MEMBER_PROPERTY); // if (node.getAST().apiLevel() == JLS2_INTERNAL) { // pos= rewriteRequiredNode(node, ClassInstanceCreation.NAME_PROPERTY); // } else { // if (isChanged(node, ClassInstanceCreation.TYPE_ARGUMENTS_PROPERTY)) { // try { // pos= getScanner().getTokenEndOffset(ITerminalSymbols.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(ITerminalSymbols.TokenNameLPAREN, pos); rewriteNodeList(node, ClassInstanceCreation.ARGUMENTS_PROPERTY, startpos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ } 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(ITerminalSymbols.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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ConditionalExpression) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ConstructorInvocation) */ public boolean visit(ConstructorInvocation node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int pos= node.getStartPosition(); if (node.getAST().apiLevel() >= AST.JLS3) { pos= rewriteOptionalTypeParameters(node, ConstructorInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false, false); //$NON-NLS-1$ } try { pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameLPAREN, pos); rewriteNodeList(node, ConstructorInvocation.ARGUMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ } catch (CoreException e) { handleException(e); } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ContinueStatement) */ public boolean visit(ContinueStatement node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } try { int offset= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNamecontinue, node.getStartPosition()); rewriteNode(node, ContinueStatement.LABEL_PROPERTY, offset, ASTRewriteFormatter.SPACE); // space between continue and label } catch (CoreException e) { handleException(e); } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(DoStatement) */ 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(ITerminalSymbols.TokenNamedo, pos); ASTNode body= (ASTNode) event.getOriginalValue(); int bodyEnd= body.getStartPosition() + body.getLength(); int endPos= getScanner().getTokenStartOffset(ITerminalSymbols.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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(EmptyStatement) */ public boolean visit(EmptyStatement node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } changeNotSupported(node); // no modification possible return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ExpressionStatement) */ public boolean visit(ExpressionStatement node) { // expression if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteRequiredNode(node, ExpressionStatement.EXPRESSION_PROPERTY); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(FieldAccess) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(FieldDeclaration) */ 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, FieldDeclaration.MODIFIERS_PROPERTY, pos); } else { rewriteModifiers2(node, FieldDeclaration.MODIFIERS2_PROPERTY, pos); } pos= rewriteRequiredNode(node, FieldDeclaration.TYPE_PROPERTY); rewriteNodeList(node, FieldDeclaration.FRAGMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ForStatement) */ 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(ITerminalSymbols.TokenNameLPAREN, pos); pos= rewriteNodeList(node, ForStatement.INITIALIZERS_PROPERTY, startOffset, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ } else { pos= doVisit(node, ForStatement.INITIALIZERS_PROPERTY, pos); } // position after first semicolon pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameSEMICOLON, pos); pos= rewriteNode(node, ForStatement.EXPRESSION_PROPERTY, pos, ASTRewriteFormatter.NONE); if (isChanged(node, ForStatement.UPDATERS_PROPERTY)) { int startOffset= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameSEMICOLON, pos); pos= rewriteNodeList(node, ForStatement.UPDATERS_PROPERTY, startOffset, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ } 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(ITerminalSymbols.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; } public boolean visit(ForInStatement node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } try { int pos= node.getStartPosition(); pos= rewriteNode(node, ForInStatement.ITERATION_VARIABLE_PROPERTY, pos, ASTRewriteFormatter.NONE); // position after first semicolon pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNamein, pos); pos= rewriteNode(node, ForInStatement.COLLECTION_PROPERTY, pos, ASTRewriteFormatter.NONE); RewriteEvent bodyEvent= getEvent(node, ForInStatement.BODY_PROPERTY); if (bodyEvent != null && bodyEvent.getChangeKind() == RewriteEvent.REPLACED) { int startOffset= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameRPAREN, pos); rewriteBodyNode(node, ForInStatement.BODY_PROPERTY, startOffset, -1, getIndent(node.getStartPosition()), this.formatter.FOR_BLOCK); // body } else { voidVisit(node, ForInStatement.BODY_PROPERTY); } } catch (CoreException e) { handleException(e); } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(IfStatement) */ 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 { pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameRPAREN, pos); // after the closing parent 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(ITerminalSymbols.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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ImportDeclaration) */ public boolean visit(ImportDeclaration node) { if (node.isFileImport()) return false; if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } if (node.getAST().apiLevel() >= AST.JLS3) { RewriteEvent event= getEvent(node, ImportDeclaration.STATIC_PROPERTY); if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { try { int pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameimport, node.getStartPosition()); boolean wasStatic= ((Boolean) event.getOriginalValue()).booleanValue(); if (wasStatic) { int endPos= getScanner().getTokenEndOffset(ITerminalSymbols.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(ITerminalSymbols.TokenNameSEMICOLON, pos); doTextRemove(pos, endPos - pos, getEditGroup(event)); } catch (CoreException e) { handleException(e); } } } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(InfixExpression) */ public boolean visit(InfixExpression node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int pos= rewriteRequiredNode(node, InfixExpression.LEFT_OPERAND_PROPERTY); boolean needsNewOperation= isChanged(node, InfixExpression.OPERATOR_PROPERTY); String operation= getNewValue(node, InfixExpression.OPERATOR_PROPERTY).toString(); if (needsNewOperation) { replaceOperation(pos, operation, getEditGroup(node, InfixExpression.OPERATOR_PROPERTY)); } 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(Initializer) */ 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, Initializer.MODIFIERS_PROPERTY, pos); } else { rewriteModifiers2(node, Initializer.MODIFIERS2_PROPERTY, pos); } rewriteRequiredNode(node, Initializer.BODY_PROPERTY); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(InstanceofExpression) */ 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; } public 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); } } } public void ensureSpaceBeforeReplace(ASTNode node, ChildPropertyDescriptor desc, int offset, int numTokenBefore) { // bug 103970 if (getChangeKind(node, desc) == RewriteEvent.REPLACED) { try { while (numTokenBefore > 0) { offset= getScanner().getNextEndOffset(offset, true); numTokenBefore--; } if (offset == getExtendedOffset((ASTNode) getOriginalValue(node, desc))) { doTextInsert(offset, String.valueOf(' '), getEditGroup(node, desc)); } } catch (CoreException e) { handleException(e); } } } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(Javadoc) */ public boolean visit(JSdoc node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int startPos= node.getStartPosition() + 3; String separator= getLineDelimiter() + getIndentAtOffset(node.getStartPosition()) + " * "; //$NON-NLS-1$ rewriteNodeList(node, JSdoc.TAGS_PROPERTY, startPos, separator, separator); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(LabeledStatement) */ public boolean visit(LabeledStatement node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteRequiredNode(node, LabeledStatement.LABEL_PROPERTY); rewriteRequiredNode(node, LabeledStatement.BODY_PROPERTY); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(FunctionInvocation) */ public boolean visit(FunctionInvocation node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int pos= rewriteOptionalQualifier(node, FunctionInvocation.EXPRESSION_PROPERTY, node.getStartPosition()); if (node.getAST().apiLevel() >= AST.JLS3) { pos= rewriteOptionalTypeParameters(node, FunctionInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false, false); //$NON-NLS-1$ } pos= rewriteNode(node, FunctionInvocation.NAME_PROPERTY,pos, ASTRewriteFormatter.NONE); if (isChanged(node, FunctionInvocation.ARGUMENTS_PROPERTY)) { // eval position after opening parent try { int startOffset= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameLPAREN, pos); rewriteNodeList(node, FunctionInvocation.ARGUMENTS_PROPERTY, startOffset, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ } catch (CoreException e) { handleException(e); } } else { voidVisit(node, FunctionInvocation.ARGUMENTS_PROPERTY); } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(NullLiteral) */ public boolean visit(NullLiteral node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } changeNotSupported(node); // no modification possible return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(NumberLiteral) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(PackageDeclaration) */ public boolean visit(PackageDeclaration node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } if (node.getAST().apiLevel() >= AST.JLS3) { int pos= rewriteJavadoc(node, PackageDeclaration.JAVADOC_PROPERTY); } rewriteRequiredNode(node, PackageDeclaration.NAME_PROPERTY); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ParenthesizedExpression) */ public boolean visit(ParenthesizedExpression node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteRequiredNode(node, ParenthesizedExpression.EXPRESSION_PROPERTY); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(PostfixExpression) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(PrefixExpression) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(PrimitiveType) */ public boolean visit(PrimitiveType node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(QualifiedName) */ public boolean visit(QualifiedName node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteRequiredNode(node, QualifiedName.QUALIFIER_PROPERTY); rewriteRequiredNode(node, QualifiedName.NAME_PROPERTY); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(SimpleName) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(SimpleType) */ public boolean visit(SimpleType node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteRequiredNode(node, SimpleType.NAME_PROPERTY); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(SingleVariableDeclaration) */ public boolean visit(SingleVariableDeclaration node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int pos= node.getStartPosition(); // if (node.getAST().apiLevel() == JLS2_INTERNAL) { // rewriteModifiers(node, SingleVariableDeclaration.MODIFIERS_PROPERTY, pos); // } else { // rewriteModifiers2(node, SingleVariableDeclaration.MODIFIERS2_PROPERTY, pos); // } if (!node.getType().isInferred()) pos= rewriteRequiredNode(node, SingleVariableDeclaration.TYPE_PROPERTY); if (node.getAST().apiLevel() >= AST.JLS3) { if (isChanged(node, SingleVariableDeclaration.VARARGS_PROPERTY)) { if (getNewValue(node, SingleVariableDeclaration.VARARGS_PROPERTY).equals(Boolean.TRUE)) { doTextInsert(pos, "...", getEditGroup(node, SingleVariableDeclaration.VARARGS_PROPERTY)); //$NON-NLS-1$ } else { try { int ellipsisEnd= getScanner().getNextEndOffset(pos, true); doTextRemove(pos, ellipsisEnd - pos, getEditGroup(node, SingleVariableDeclaration.VARARGS_PROPERTY)); } catch (CoreException e) { handleException(e); } } } } pos= rewriteRequiredNode(node, SingleVariableDeclaration.NAME_PROPERTY); int extraDims= rewriteExtraDimensions(node, SingleVariableDeclaration.EXTRA_DIMENSIONS_PROPERTY, pos); if (extraDims > 0) { int kind= getChangeKind(node, SingleVariableDeclaration.INITIALIZER_PROPERTY); if (kind == RewriteEvent.REMOVED) { try { pos= getScanner().getPreviousTokenEndOffset(ITerminalSymbols.TokenNameEQUAL, pos); } catch (CoreException e) { handleException(e); } } else { pos= node.getStartPosition() + node.getLength(); // insert pos } } rewriteNode(node, SingleVariableDeclaration.INITIALIZER_PROPERTY, pos, this.formatter.VAR_INITIALIZER); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(StringLiteral) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(SuperConstructorInvocation) */ public boolean visit(SuperConstructorInvocation node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int pos= rewriteOptionalQualifier(node, SuperConstructorInvocation.EXPRESSION_PROPERTY, node.getStartPosition()); if (node.getAST().apiLevel() >= AST.JLS3) { pos= rewriteOptionalTypeParameters(node, SuperConstructorInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false, false); //$NON-NLS-1$ } if (isChanged(node, SuperConstructorInvocation.ARGUMENTS_PROPERTY)) { // eval position after opening parent try { pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameLPAREN, pos); rewriteNodeList(node, SuperConstructorInvocation.ARGUMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ } catch (CoreException e) { handleException(e); } } else { voidVisit(node, SuperConstructorInvocation.ARGUMENTS_PROPERTY); } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(SuperFieldAccess) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(SuperMethodInvocation) */ public boolean visit(SuperMethodInvocation node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int pos= rewriteOptionalQualifier(node, SuperMethodInvocation.QUALIFIER_PROPERTY, node.getStartPosition()); if (node.getAST().apiLevel() >= AST.JLS3) { if (isChanged(node, SuperMethodInvocation.TYPE_ARGUMENTS_PROPERTY)) { try { pos= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameDOT, pos); rewriteOptionalTypeParameters(node, SuperMethodInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false, false); //$NON-NLS-1$ } 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(ITerminalSymbols.TokenNameLPAREN, pos); rewriteNodeList(node, SuperMethodInvocation.ARGUMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ } catch (CoreException e) { handleException(e); } } else { voidVisit(node, SuperMethodInvocation.ARGUMENTS_PROPERTY); } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(SwitchCase) */ 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 { public SwitchListRewriter(int initialIndent) { super(initialIndent, 0); } protected int getNodeIndent(int nodeIndex) { int indent= getInitialIndent(); ASTNode node= (ASTNode) this.list[nodeIndex].getOriginalValue(); if (node == null) { node= (ASTNode) this.list[nodeIndex].getNewValue(); } if (node.getNodeType() != ASTNode.SWITCH_CASE) { indent++; } return indent; } } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(SwitchStatement) */ 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(ITerminalSymbols.TokenNameLBRACE, pos); int insertIndent= getIndent(node.getStartPosition()) + 1; 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ThisExpression) */ public boolean visit(ThisExpression node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteOptionalQualifier(node, ThisExpression.QUALIFIER_PROPERTY, node.getStartPosition()); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(ThrowStatement) */ public boolean visit(ThrowStatement node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteRequiredNode(node, ThrowStatement.EXPRESSION_PROPERTY); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(TryStatement) */ public boolean visit(TryStatement node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(TypeDeclarationStatement) */ public boolean visit(TypeDeclarationStatement node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } if (node.getAST().apiLevel() == JLS2_INTERNAL) { rewriteRequiredNode(node, TypeDeclarationStatement.TYPE_DECLARATION_PROPERTY); } else { rewriteRequiredNode(node, TypeDeclarationStatement.DECLARATION_PROPERTY); } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(TypeLiteral) */ public boolean visit(TypeLiteral node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteRequiredNode(node, TypeLiteral.TYPE_PROPERTY); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(VariableDeclarationExpression) */ 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, VariableDeclarationExpression.MODIFIERS_PROPERTY, pos); // } else { // rewriteModifiers2(node, VariableDeclarationExpression.MODIFIERS2_PROPERTY, pos); // } if (!node.getType().isInferred()) pos= rewriteRequiredNode(node, VariableDeclarationExpression.TYPE_PROPERTY); rewriteNodeList(node, VariableDeclarationExpression.FRAGMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(VariableDeclarationFragment) */ public boolean visit(VariableDeclarationFragment node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int pos= rewriteRequiredNode(node, VariableDeclarationFragment.NAME_PROPERTY); int extraDims= rewriteExtraDimensions(node, VariableDeclarationFragment.EXTRA_DIMENSIONS_PROPERTY, pos); if (extraDims > 0) { int kind= getChangeKind(node, VariableDeclarationFragment.INITIALIZER_PROPERTY); if (kind == RewriteEvent.REMOVED) { try { pos= getScanner().getPreviousTokenEndOffset(ITerminalSymbols.TokenNameEQUAL, pos); } catch (CoreException e) { handleException(e); } } else { pos= node.getStartPosition() + node.getLength(); // insert pos } } rewriteNode(node, VariableDeclarationFragment.INITIALIZER_PROPERTY, pos, this.formatter.VAR_INITIALIZER); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(VariableDeclarationStatement) */ 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, VariableDeclarationStatement.MODIFIERS_PROPERTY, pos); // } else { // rewriteModifiers2(node, VariableDeclarationStatement.MODIFIERS2_PROPERTY, pos); // } if (!node.getType().isInferred()) pos= rewriteRequiredNode(node, VariableDeclarationStatement.TYPE_PROPERTY); rewriteNodeList(node, VariableDeclarationStatement.FRAGMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(WhileStatement) */ 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(ITerminalSymbols.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; } public boolean visit(WithStatement node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int pos= rewriteRequiredNode(node, WithStatement.EXPRESSION_PROPERTY); try { if (isChanged(node, WithStatement.BODY_PROPERTY)) { int startOffset= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameRPAREN, pos); rewriteBodyNode(node, WithStatement.BODY_PROPERTY, startOffset, -1, getIndent(node.getStartPosition()), this.formatter.WHILE_BLOCK); // body } else { voidVisit(node, WithStatement.BODY_PROPERTY); } } catch (CoreException e) { handleException(e); } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.MemberRef) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.FunctionRef) */ public boolean visit(FunctionRef node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteNode(node, FunctionRef.QUALIFIER_PROPERTY, node.getStartPosition(), ASTRewriteFormatter.NONE); int pos= rewriteRequiredNode(node, FunctionRef.NAME_PROPERTY); if (isChanged(node, FunctionRef.PARAMETERS_PROPERTY)) { // eval position after opening parent try { int startOffset= getScanner().getTokenEndOffset(ITerminalSymbols.TokenNameLPAREN, pos); rewriteNodeList(node, FunctionRef.PARAMETERS_PROPERTY, startOffset, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ } catch (CoreException e) { handleException(e); } } else { voidVisit(node, FunctionRef.PARAMETERS_PROPERTY); } return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.FunctionRefParameter) */ public boolean visit(FunctionRefParameter node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int pos= rewriteRequiredNode(node, FunctionRefParameter.TYPE_PROPERTY); if (node.getAST().apiLevel() >= AST.JLS3) { if (isChanged(node, FunctionRefParameter.VARARGS_PROPERTY)) { if (getNewValue(node, FunctionRefParameter.VARARGS_PROPERTY).equals(Boolean.TRUE)) { doTextInsert(pos, "...", getEditGroup(node, FunctionRefParameter.VARARGS_PROPERTY)); //$NON-NLS-1$ } else { try { int ellipsisEnd= getScanner().getNextEndOffset(pos, true); doTextRemove(pos, ellipsisEnd - pos, getEditGroup(node, FunctionRefParameter.VARARGS_PROPERTY)); } catch (CoreException e) { handleException(e); } } } } rewriteNode(node, FunctionRefParameter.NAME_PROPERTY, pos, ASTRewriteFormatter.SPACE); return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.TagElement) */ 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(); } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.TextElement) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.EnhancedForStatement) */ 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(ITerminalSymbols.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; } public boolean visit(ListExpression node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } int startPos= node.getStartPosition(); rewriteNodeList(node, ListExpression.EXPRESSIONS_PROPERTY, startPos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ return false; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.Modifier) */ 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; } /* (non-Javadoc) * @see org.eclipse.wst.jsdt.core.dom.ASTVisitor#visit(org.eclipse.wst.jsdt.core.dom.QualifiedType) */ public boolean visit(QualifiedType node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } rewriteRequiredNode(node, QualifiedType.QUALIFIER_PROPERTY); rewriteRequiredNode(node, QualifiedType.NAME_PROPERTY); return false; } public boolean visit(UndefinedLiteral node) { if (!hasChildrenChanges(node)) { return doVisitUnchangedChildren(node); } changeNotSupported(node); // no modification possible return false; } final void handleException(Throwable e) { IllegalArgumentException runtimeException= new IllegalArgumentException("Document does not match the AST"); //$NON-NLS-1$ runtimeException.initCause(e); throw runtimeException; } }