/*******************************************************************************
* Copyright (c) 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
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.core.ast.rewrite;
import java.io.IOException;
import java.util.*;
import java_cup.runtime.Symbol;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dltk.ast.Modifiers;
import org.eclipse.dltk.compiler.util.ScannerHelper;
import org.eclipse.jface.text.IDocument;
import org.eclipse.php.core.compiler.PHPFlags;
import org.eclipse.php.internal.core.Logger;
import org.eclipse.php.internal.core.PHPCorePlugin;
import org.eclipse.php.internal.core.PHPVersion;
import org.eclipse.php.internal.core.ast.nodes.*;
import org.eclipse.php.internal.core.ast.rewrite.ASTRewriteFormatter.BlockContext;
import org.eclipse.php.internal.core.ast.rewrite.ASTRewriteFormatter.NodeMarker;
import org.eclipse.php.internal.core.ast.rewrite.ASTRewriteFormatter.Prefix;
import org.eclipse.php.internal.core.ast.rewrite.NodeInfoStore.CopyPlaceholderData;
import org.eclipse.php.internal.core.ast.rewrite.NodeInfoStore.StringPlaceholderData;
import org.eclipse.php.internal.core.ast.rewrite.RewriteEventStore.CopySourceInfo;
import org.eclipse.php.internal.core.ast.rewrite.TargetSourceRangeComputer.SourceRange;
import org.eclipse.php.internal.core.ast.scanner.AstLexer;
import org.eclipse.php.internal.core.ast.visitor.AbstractVisitor;
import org.eclipse.text.edits.*;
/**
* 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 AbstractVisitor {
private static final String CURLY_CLOSE = "}"; //$NON-NLS-1$
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 IDocument document;
private final LineInformation lineInfo;
private final ASTRewriteFormatter formatter;
private final NodeInfoStore nodeInfos;
private final TargetSourceRangeComputer extendedSourceRangeComputer;
private final LineCommentEndOffsets lineCommentEndOffsets;
private final AstLexer scanner;
/**
* Constructor for ASTRewriteAnalyzer.
*
* @param scanner
* An {@link AstLexer} scanner.
* @param document
* The IDocument that contains 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 options (formatting/compliance) or
* <code>null</code>.
* @param extendedSourceRangeComputer
* the source range computer to use
*/
public ASTRewriteAnalyzer(AstLexer scanner, IDocument document,
LineInformation lineInfo, String lineDelim, TextEdit rootEdit,
RewriteEventStore eventStore, NodeInfoStore nodeInfos,
List comments, Map options,
TargetSourceRangeComputer extendedSourceRangeComputer) {
this.scanner = scanner;
this.eventStore = eventStore;
this.document = document;
this.content = document.get().toCharArray();
this.lineInfo = lineInfo;
this.nodeInfos = nodeInfos;
this.tokenScanner = null;
this.currentEdit = rootEdit;
this.sourceCopyInfoToEdit = new IdentityHashMap();
this.sourceCopyEndNodes = new Stack();
this.formatter = new ASTRewriteFormatter(document, nodeInfos,
eventStore, options, lineDelim, scanner.getPHPVersion(), true);
this.extendedSourceRangeComputer = extendedSourceRangeComputer;
this.lineCommentEndOffsets = new LineCommentEndOffsets(comments);
}
final TokenScanner getScanner() {
if (this.tokenScanner == null) {
try {
this.tokenScanner = new TokenScanner(scanner, content);
} catch (IOException e) {
Logger.logException(e);
}
}
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.getStart(), 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 (isInsertUseStatement && insertString.trim().length() > 0) {
insertString = insertString.replaceAll("\r", "").replaceAll("\n", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
""); //$NON-NLS-1$
}
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.getStart());
}
}
return getInitialIndent();
}
return getIndent(node.getStart());
}
protected int getStartOfNextNode(int nextIndex, int defaultPos) {
// workaround for bug 393253
if (isInsertUseStatement
&& nextIndex > 0
&& this.list[nextIndex].getChangeKind() == RewriteEvent.INSERTED
&& this.list[nextIndex - 1].getChangeKind() == RewriteEvent.UNCHANGED
&& this.list[nextIndex].getNewValue() instanceof UseStatement
&& this.list[nextIndex - 1].getOriginalValue() instanceof UseStatement) {
if (((UseStatement) this.list[nextIndex].getNewValue())
.getStart() > 0) {
return ((UseStatement) this.list[nextIndex].getNewValue())
.getStart();
}
}
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 (isInsertUseStatement) {
Program program = parent.getProgramRoot();
List<Comment> comments = program.comments();
if (comments != null && comments.size() > 0) {
for (Comment comment : comments) {
if (comment.getStart() >= parent.getStart()
&& comment.getStart() < currPos) {
currPos = comment.getStart();
break;
}
}
}
}
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 rewriteDocumentation(ASTNode node,
StructuralPropertyDescriptor property) {
int pos = rewriteNode(node, property, node.getStart(),
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(
SymbolsProvider.getSymbol(
SymbolsProvider.OBJECT_OP_SYMBOL_ID,
scanner.getPHPVersion()),
node.getStart() + 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(
SymbolsProvider.getSymbol(
SymbolsProvider.OBJECT_OP_SYMBOL_ID,
scanner.getPHPVersion()), offset + length);
} catch (CoreException e) {
handleException(e);
}
break;
}
}
}
Object node = getOriginalValue(parent, property);
if (node == null) {
return startPos;
}
ASTNode astNode = (ASTNode) node;
int pos = doVisit(astNode);
try {
return getScanner().getTokenEndOffset(
SymbolsProvider.getSymbol(SymbolsProvider.DOT_SYMBOL_ID,
scanner.getPHPVersion()), 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.getType();
int nextKind = next.getType();
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.getType() == nextKind
&& last.getType() == 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(
SymbolsProvider.getSymbol(
SymbolsProvider.LESS_ID,
scanner.getPHPVersion()), 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(
SymbolsProvider.getSymbol(
SymbolsProvider.GREATER_ID,
scanner.getPHPVersion()), 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(
SymbolsProvider.getSymbol(SymbolsProvider.GREATER_ID,
scanner.getPHPVersion()), 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);
}
/*
* Rewrite the dollar property when dealing with a variable.
*/
private void rewriteVariableDollar(Variable variable) {
// Make the necessary changes to add or remove the $ sign.
RewriteEvent event = getEvent(variable, variable.getDollaredProperty());
if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) {
TextEditGroup editGroup = getEditGroup(event);
if ((Boolean) event.getNewValue()) {
// Add a dollar sign to the variable
this.doTextInsert(variable.getStart(), "$", editGroup); //$NON-NLS-1$
} else {
// Remove the dollar sign from the variable
this.doTextRemove(variable.getStart(), 1, editGroup);
}
}
}
/*
* Next token is a left brace. Returns the offset of the open brace.
*
* @throws CoreException
*/
private int getLeftBraceStartPosition(int pos) throws CoreException {
return getSymbolStartPosition(
pos,
SymbolsProvider.getSymbol(SymbolsProvider.LBRACE_ID,
scanner.getPHPVersion()));
}
/*
* Next token is a right brace. Returns the offset of the closing brace.
*
* @throws CoreException
*/
private int getRightBraceStartPosition(int pos) throws CoreException {
return getSymbolStartPosition(
pos,
SymbolsProvider.getSymbol(SymbolsProvider.RBRACE_ID,
scanner.getPHPVersion()));
}
/*
* Next token is a left parentheses. Returns the offset of the open
* parentheses.
*
* @throws CoreException
*/
private int getLeftParenthesesStartPosition(int pos) throws CoreException {
return getSymbolStartPosition(
pos,
SymbolsProvider.getSymbol(SymbolsProvider.LPAREN_ID,
scanner.getPHPVersion()));
}
/*
* Next token is a right parentheses. Returns the offset of the closing
* parentheses.
*
* @throws CoreException
*/
private int getRightParenthesesStartPosition(int pos) throws CoreException {
return getSymbolStartPosition(
pos,
SymbolsProvider.getSymbol(SymbolsProvider.RPAREN_ID,
scanner.getPHPVersion()));
}
/*
* Next token is a left bracket. Returns the offset of the open bracket.
*
* @throws CoreException
*/
private int getLeftBracketStartPosition(int pos) throws CoreException {
return getSymbolStartPosition(
pos,
SymbolsProvider.getSymbol(SymbolsProvider.LBRACKET_ID,
scanner.getPHPVersion()));
}
/*
* Next token is a right bracket. Returns the offset of the closing bracket.
*
* @throws CoreException
*/
private int getRightBracketStartPosition(int pos) throws CoreException {
return getSymbolStartPosition(
pos,
SymbolsProvider.getSymbol(SymbolsProvider.RBRACKET_ID,
scanner.getPHPVersion()));
}
/*
* A general call to get the scanner's start offset of the Symbol token.
*/
private int getSymbolStartPosition(int pos, Symbol sym)
throws CoreException {
return getScanner().getTokenStartOffset(sym, pos);
}
final int getIndent(int offset) {
return this.formatter.computeIndentUnits(getIndentOfLine(offset));
}
private int getCurrentLineStart(String str, int pos) {
for (int i = pos - 1; i >= 0; i--) {
char ch = str.charAt(i);
if (IndentManipulation.isLineDelimiterChar(ch)) {
return i + 1;
}
}
return 0;
}
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 {
int lineOffset = getCurrentLineStart(formatted, offset);
String destIndentString = (lineOffset == 0) ? this.formatter
.createIndentString(initialIndentLevel)
: this.formatter.getIndentString(getCurrentLine(
formatted, offset));
/*
* 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()
.getStart());
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);
if (node instanceof MethodStub && insertStr.startsWith(CURLY_CLOSE)) {
doTextInsert(insertOffset, getLineDelimiter(), editGroup);
String destIndentString = this.formatter
.getIndentString(getCurrentLine(formatted, currPos));
doTextInsert(insertOffset, destIndentString, editGroup);
}
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();
int newModifiers = (Integer) event.getNewValue();
TextEditGroup editGroup = getEditGroup(event);
TokenScanner scanner = getScanner();
Symbol tok = scanner.readNext(offset/* , false */);
int startPos = scanner.getCurrentStartOffset();
int nextStart = startPos;
// prepare the modifiers 'syms'
PHPVersion phpVersion = this.scanner.getPHPVersion();
int modifiers[] = new int[] {
SymbolsProvider.getModifierSym("public", phpVersion), //$NON-NLS-1$
SymbolsProvider.getModifierSym("private", phpVersion), //$NON-NLS-1$
SymbolsProvider.getModifierSym("protected", phpVersion), //$NON-NLS-1$
SymbolsProvider.getModifierSym("static", phpVersion), //$NON-NLS-1$
SymbolsProvider.getModifierSym("abstract", phpVersion), //$NON-NLS-1$
SymbolsProvider.getModifierSym("final", phpVersion) }; //$NON-NLS-1$
loop: while (true) {
if (TokenScanner.isComment(tok)) {
tok = scanner.readNext(/* true */); // next non-comment
// token
}
boolean keep = true;
if (tok == null) {
break loop;
}
if (tok.sym == modifiers[0]) {
keep = PHPFlags.isPublic(newModifiers);
} else if (tok.sym == modifiers[1]) {
keep = PHPFlags.isPrivate(newModifiers);
} else if (tok.sym == modifiers[2]) {
keep = PHPFlags.isProtected(newModifiers);
} else if (tok.sym == modifiers[3]) {
keep = PHPFlags.isStatic(newModifiers);
} else if (tok.sym == modifiers[4]) {
keep = PHPFlags.isAbstract(newModifiers);
} else if (tok.sym == modifiers[5]) {
keep = PHPFlags.isFinal(newModifiers);
} else {
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
& (Modifiers.AccPublic | Modifiers.AccPrivate | Modifiers.AccProtected);
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.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.ListRewriter
* #getSeparatorString(int)
*/
protected String getSeparatorString(int nodeIndex) {
// ASTNode curr = getNewNode(nodeIndex);
// if (curr instanceof Annotation) {
// return
// this.annotationSeparation.getPrefix(getNodeIndent(nodeIndex +
// 1));
// }
// TODO
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);
// }
// }
//
// Prefix formatterPrefix;
// if (property == SingleVariableDeclaration.MODIFIERS2_PROPERTY)
// formatterPrefix = this.formatter.PARAM_ANNOTATION_SEPARATION;
// else
// formatterPrefix = this.formatter.ANNOTATION_SEPARATION;
//
// int endPos = new ModifierRewriter(formatterPrefix).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 = formatterPrefix.getPrefix(getIndent(pos));
// } else {
// separator = String.valueOf(' ');
// }
// doTextInsert(endPos, separator, getEditGroup(lastChild));
// }
// } catch (CoreException e) {
// handleException(e);
// }
// return endPos;
// TODO
return 0;
}
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();
if (parent instanceof IOperationNode) {
newOperation = ((IOperationNode) parent)
.getOperationString((Integer) event.getNewValue());
} else {
throw new CoreException(new Status(IStatus.ERROR,
PHPCorePlugin.ID,
"The node must be an IOperationNode")); //$NON-NLS-1$
}
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.jdt.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.jdt.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.jdt.core.dom.ASTVisitor#visit(Program)
*/
public boolean visit(Program node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
int pos = content.length; // TODO - Check if this is right (using 0
// cause for the code to be inserted before
// the <?php section).
rewriteNodeList(node, Program.STATEMENTS_PROPERTY, pos, "", //$NON-NLS-1$
getLineDelimiter());
// int startPos = rewriteNode(node, Program.PACKAGE_PROPERTY, 0,
// ASTRewriteFormatter.NONE);
//
// if (getChangeKind(node, Program.PACKAGE_PROPERTY) ==
// RewriteEvent.INSERTED) {
// doTextInsert(0, getLineDelimiter(), getEditGroup(node,
// Program.PACKAGE_PROPERTY));
// }
//
// startPos = rewriteParagraphList(node, Program.IMPORTS_PROPERTY,
// startPos, 0, 0, 2);
// rewriteParagraphList(node, Program.TYPES_PROPERTY, startPos, 0, -1,
// 2);
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(TypeDeclaration)
*/
public boolean visit(TypeDeclaration node) {
// Return false.
// There is no need to visit it, all the implementation is done in the
// extending ClassDeclaration and InterfaceDeclaration.
return false;
}
private void rewriteReturnType(MethodDeclaration node,
boolean isConstructor, boolean isConstructorChange) {
// TODO
// ChildPropertyDescriptor property = (node.getAST().apiLevel() ==
// PHP4_INTERNAL) ? MethodDeclaration.RETURN_TYPE_PROPERTY :
// MethodDeclaration.RETURN_TYPE2_PROPERTY;
//
// // weakness in the AST: return type can exist, even if missing in
// source
// ASTNode originalReturnType = (ASTNode) getOriginalValue(node,
// property);
// boolean returnTypeExists = originalReturnType != null &&
// originalReturnType.getStart() != -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,
// MethodDeclaration.NAME_PROPERTY);
// int nextStart = originalMethodName.getStart(); // 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.jdt.core.dom.ASTVisitor#visit(MethodDeclaration)
*/
public boolean visit(MethodDeclaration node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteModifiers(node, MethodDeclaration.MODIFIER_PROPERTY,
node.getStart());
rewriteRequiredNode(node, MethodDeclaration.FUNCTION_PROPERTY);
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(Block)
*/
public boolean visit(Block node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
int blockStart = node.getStart();
int startIndent = getIndent(node.getStart()) + 1;
rewriteParagraphList(node, Block.STATEMENTS_PROPERTY, blockStart + 1,
startIndent, 0, 1);
// Check for While, For, If, ForEach, Switch
// In each case, the basic form of the alternate syntax is to change the
// opening brace to a colon (:)
// and the closing brace to endif;, endwhile;, endfor;, endforeach;, or
// endswitch;, respectively.
RewriteEvent event = getEvent(node, Block.IS_CURLY_PROPERTY);
if (event != null) {
TextEditGroup editGroup = getEditGroup(event);
boolean shouldBeCurly = (Boolean) event.getNewValue();
StructuralPropertyDescriptor propertyDescriptor = node
.getLocationInParent();
if (propertyDescriptor == IfStatement.TRUE_STATEMENT_PROPERTY
|| propertyDescriptor == IfStatement.FALSE_STATEMENT_PROPERTY) {
rewriteIfBlocks(node, editGroup, shouldBeCurly);
} else if (propertyDescriptor == WhileStatement.BODY_PROPERTY) {
Symbol symbol = SymbolsProvider.getSymbol(
SymbolsProvider.END_WHILE_ID, scanner.getPHPVersion());
rewriteBlock(node, editGroup, shouldBeCurly, "endwhile", symbol); //$NON-NLS-1$
} else if (propertyDescriptor == ForStatement.BODY_PROPERTY) {
Symbol symbol = SymbolsProvider.getSymbol(
SymbolsProvider.END_FOR_ID, scanner.getPHPVersion());
rewriteBlock(node, editGroup, shouldBeCurly, "endfor", symbol); //$NON-NLS-1$
} else if (propertyDescriptor == ForEachStatement.STATEMENT_PROPERTY) {
Symbol symbol = SymbolsProvider
.getSymbol(SymbolsProvider.END_FOREACH_ID,
scanner.getPHPVersion());
rewriteBlock(node, editGroup, shouldBeCurly, "endforeach", //$NON-NLS-1$
symbol);
} else if (propertyDescriptor == SwitchStatement.BODY_PROPERTY) {
Symbol symbol = SymbolsProvider.getSymbol(
SymbolsProvider.END_SWITCH_ID, scanner.getPHPVersion());
rewriteBlock(node, editGroup, shouldBeCurly, "endswitch", //$NON-NLS-1$
symbol);
}
}
return false;
}
/*
* Rewrite the If statement blocks from curly to 'Alternative syntax'
* blocks.
*
* @param node
*
* @param editGroup
*
* @param shouldBeCurly
*/
private void rewriteIfBlocks(Block node, TextEditGroup editGroup,
boolean shouldBeCurly) {
int blockStart = node.getStart();
int blockEnd = node.getEnd() - 1;
StructuralPropertyDescriptor propertyDescriptor = node
.getLocationInParent();
IfStatement ifStatement = (IfStatement) node.getParent();
if (propertyDescriptor == IfStatement.TRUE_STATEMENT_PROPERTY) {
if (shouldBeCurly) {
// Change the if's open block char to the opening brace char
doTextReplace(blockStart, 1, "{", editGroup); //$NON-NLS-1$
// Change the closing mark to be a closing brace
doTextInsert(blockEnd + 1, "\n}", editGroup); //$NON-NLS-1$
// remove the endif token at this stage
Symbol endIfSymbol = SymbolsProvider.getSymbol(
SymbolsProvider.END_IF_ID, scanner.getPHPVersion());
try {
int endifPos = getScanner().getTokenStartOffset(
endIfSymbol, blockEnd);
// search for the semicolon that might appear after that
// token
int semicolonPos = scanToSemicolon(endifPos + 5);
doTextRemove(endifPos, semicolonPos - endifPos + 1,
editGroup);
} catch (Exception e) {
// Should not happen, since the if should have an endif
handleException(e);
}
} else {
doTextReplace(blockStart, 1, ":", editGroup); //$NON-NLS-1$
// In case that we don't have a false statement, add the endif
// word
if (ifStatement.getFalseStatement() == null) {
doTextReplace(blockEnd, 1, "endif;", editGroup); //$NON-NLS-1$
} else {
doTextRemove(blockEnd, 1, editGroup);
}
}
} else if (propertyDescriptor == IfStatement.FALSE_STATEMENT_PROPERTY) {
// Change the if's closing block char to an endif; or to a closing
// brace
if (shouldBeCurly) {
// replace the opening colon char to a brace char
doTextReplace(blockStart, 1, "{", editGroup); //$NON-NLS-1$
// close the block with a brace
doTextInsert(blockEnd + 1, "\n}", editGroup); //$NON-NLS-1$
} else {
doTextReplace(blockStart, 1, ":", editGroup); //$NON-NLS-1$
// End the if statement
doTextReplace(blockEnd, 1, "endif;", editGroup); //$NON-NLS-1$
}
}
}
/*
* Rewrite a statement blocks from curly to 'Alternative syntax' blocks.
*
* @param node
*
* @param editGroup
*
* @param shouldBeCurly
*
* @param keyword The block closing keyword (e.g. endif, endwhile etc.)
*
* @param keywordSymbol The keyword Symbol
*/
private void rewriteBlock(Block node, TextEditGroup editGroup,
boolean shouldBeCurly, String keyword, Symbol keywordSymbol) {
int blockStart = node.getStart();
int blockEnd = node.getEnd();
// if (getContent()[blockEnd] != '}') {
// blockEnd++;
// }
if (shouldBeCurly) {
// Change the if's open block char to the opening brace char
doTextReplace(blockStart, 1, "{", editGroup); //$NON-NLS-1$
// Change the closing mark to be a closing brace
doTextInsert(blockEnd + 1, "\n}", editGroup); //$NON-NLS-1$
try {
// We scan for the Block end position by looking for the
// symbol's start offset.
// The search is done a bit before the block's end in order to
// cover the 'SwitchStatement' that is
// marking the end of the Block after the 'endswitch' keyword
// (unlike all the other types of blocks).
int endBlockPos = getScanner().getTokenStartOffset(
keywordSymbol, blockEnd - keyword.length());
// search for the semicolon that might appear after that token
int semicolonPos = scanToSemicolon(endBlockPos
+ keyword.length());
doTextRemove(endBlockPos, semicolonPos - endBlockPos + 1,
editGroup);
} catch (Exception e) {
// Should not happen, since the if should have the keyword
handleException(e);
}
} else {
doTextReplace(blockStart, 1, ":", editGroup); //$NON-NLS-1$
// In case that we don't have a false statement, add the keyword
doTextReplace(blockEnd - 1, 1, keyword + ';', editGroup);
}
}
/*
* Scan to the first semicolon that appears in the content after the given
* position. The scan skip all the whitespace characters and tries to locate
* the first non-whitespace that is a semicolon (;). The return value is the
* semicolon index. The given index is returned when no semicolon was found
* right after the whitespaces.
*/
private int scanToSemicolon(int startIndex) {
for (int i = startIndex; i < content.length; i++) {
if (content[i] == ';') {
return i;
}
if (content[i] != ' ' && content[i] != '\t' && content[i] != '\n'
&& content[i] != '\r') {
return startIndex;
}
}
return startIndex;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ReturnStatement)
*/
public boolean visit(ReturnStatement node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
try {
int offset = getScanner().getTokenEndOffset(
SymbolsProvider.getSymbol(SymbolsProvider.RETURN_ID,
scanner.getPHPVersion()), node.getStart());
ensureSpaceBeforeReplace(node, ReturnStatement.EXPRESSION_PROPERTY,
offset, 0);
rewriteNode(node, ReturnStatement.EXPRESSION_PROPERTY, offset,
ASTRewriteFormatter.SPACE);
} catch (CoreException e) {
handleException(e);
}
return false;
}
public boolean visit(YieldExpression node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
RewriteEvent event = getEvent(node, YieldExpression.KEY_PROPERTY);
if (event != null) {
rewriteKeyValue(node, event);
}
if (isChanged(node, YieldExpression.EXPRESSION_PROPERTY)) {
try {
int offset = node.getKey() != null ? node.getKey().getEnd()
: getScanner().getTokenEndOffset(
SymbolsProvider.getSymbol(
SymbolsProvider.YIELD_ID,
scanner.getPHPVersion()),
node.getStart());
ensureSpaceBeforeReplace(node,
YieldExpression.EXPRESSION_PROPERTY, offset, 0);
rewriteNode(node, YieldExpression.EXPRESSION_PROPERTY, offset,
ASTRewriteFormatter.SPACE);
} catch (CoreException e) {
handleException(e);
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ArrayAccess)
*/
public boolean visit(ArrayAccess node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
if (isChanged(node, ArrayAccess.DOLLARED_PROPERTY)) {
rewriteVariableDollar(node);
}
if (isChanged(node, ArrayAccess.ARRAY_TYPE_PROPERTY)) {
rewriteArrayAccessType(node);
}
return rewriteRequiredNodeVisit(node, ArrayAccess.NAME_PROPERTY,
ArrayAccess.INDEX_PROPERTY);
}
private void rewriteArrayAccessType(ArrayAccess arrayAccess) {
RewriteEvent event = getEvent(arrayAccess,
ArrayAccess.ARRAY_TYPE_PROPERTY);
if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) {
Integer original = (Integer) event.getOriginalValue();
try {
if (original.intValue() == ArrayAccess.VARIABLE_ARRAY) {
// the modification was from a variable array to a variable
// hashtable.
int openPos = getLeftBracketStartPosition(arrayAccess
.getStart());
int closePos = arrayAccess.getEnd() - 1;
TextEditGroup editGroup = getEditGroup(event);
doTextReplace(openPos, 1, "{", editGroup); //$NON-NLS-1$
doTextReplace(closePos, 1, CURLY_CLOSE, editGroup);
} else {
// the modification was from a variable hashtable to a
// variable array.
int openPos = getLeftBraceStartPosition(arrayAccess
.getStart());
int closePos = arrayAccess.getEnd() - 1;
TextEditGroup editGroup = getEditGroup(event);
doTextReplace(openPos, 1, "[", editGroup); //$NON-NLS-1$
doTextReplace(closePos, 1, "]", editGroup); //$NON-NLS-1$
}
} catch (CoreException ce) {
handleException(ce);
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ArrayCreation)
*/
public boolean visit(ArrayCreation node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteNodeList(node, ArrayCreation.ELEMENTS_PROPERTY, node.getStart(),
"", ", "); //$NON-NLS-1$ //$NON-NLS-2$
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.jdt.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.jdt.core.dom.ASTVisitor#visit(BreakStatement)
*/
public boolean visit(BreakStatement node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
try {
int offset = getScanner().getTokenEndOffset(
SymbolsProvider.getSymbol(SymbolsProvider.BREAK_ID,
scanner.getPHPVersion()), node.getStart());
rewriteNode(node, BreakStatement.EXPRESSION_PROPERTY, offset,
ASTRewriteFormatter.SPACE); // space between break and label
} catch (CoreException e) {
handleException(e);
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(CastExpression)
*/
public boolean visit(CastExpression cast) {
if (isChanged(cast, CastExpression.CASTING_TYPE_PROPERTY)) {
try {
rewriteCastType(cast);
} catch (Exception e) {
handleException(e);
}
}
return rewriteRequiredNodeVisit(cast,
CastExpression.EXPRESSION_PROPERTY);
}
private void rewriteCastType(CastExpression cast) throws CoreException {
RewriteEvent event = getEvent(cast,
CastExpression.CASTING_TYPE_PROPERTY);
if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) {
TextEditGroup editGroup = getEditGroup(event);
String castType = CastExpression.getCastType(cast.getCastingType());
int offset = cast.getStart() + 1;
int closingParenOffset = getScanner().getTokenStartOffset(
(SymbolsProvider.getSymbol(SymbolsProvider.RPAREN_ID,
scanner.getPHPVersion())), offset);
doTextReplace(offset, closingParenOffset - offset, castType,
editGroup);
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(CatchClause)
*/
public boolean visit(CatchClause node) { // catch (Exception) Block
return rewriteRequiredNodeVisit(node, CatchClause.CLASS_NAME_PROPERTY,
CatchClause.BODY_PROPERTY);
}
public boolean visit(FinallyClause node) { // catch (Exception) Block
return rewriteRequiredNodeVisit(node, FinallyClause.BODY_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ClassInstanceCreation)
*/
public boolean visit(ClassInstanceCreation node) {
rewriteRequiredNodeVisit(node, ClassInstanceCreation.CLASSNAME_PROPERTY);
if (isChanged(node, ClassInstanceCreation.CTOR_PARAMS_PROPERTY)) {
try {
int pos = getLeftParenthesesStartPosition(node.getStart()) + 1;
rewriteNodeList(node,
ClassInstanceCreation.CTOR_PARAMS_PROPERTY, pos, "", //$NON-NLS-1$
", "); //$NON-NLS-1$
} catch (Exception e) {
handleException(e);
}
}
if (isChanged(node,
ClassInstanceCreation.CHAINING_INSTANCE_CALL_PROPERTY)) {
rewriteRequiredNodeVisit(node,
ClassInstanceCreation.CHAINING_INSTANCE_CALL_PROPERTY);
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ConditionalExpression)
*/
public boolean visit(ConditionalExpression node) { // expression ?
// thenExpression :
// elseExpression
return rewriteRequiredNodeVisit(node,
ConditionalExpression.CONDITION_PROPERTY,
ConditionalExpression.IF_TRUE_PROPERTY,
ConditionalExpression.IF_FALSE_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ContinueStatement)
*/
public boolean visit(ContinueStatement node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
try {
int offset = getScanner().getTokenEndOffset(
SymbolsProvider.getSymbol(SymbolsProvider.CONTINUE_ID,
scanner.getPHPVersion()), node.getStart());
rewriteNode(node, ContinueStatement.EXPRESSION_PROPERTY, offset,
ASTRewriteFormatter.SPACE); // space between continue and
// label
} catch (CoreException e) {
handleException(e);
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(DoStatement)
*/
public boolean visit(DoStatement node) { // do statement while expression
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
int pos = node.getStart();
try {
RewriteEvent event = getEvent(node, DoStatement.BODY_PROPERTY);
if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) {
int startOffset = getScanner().getTokenEndOffset(
SymbolsProvider.getSymbol(SymbolsProvider.DO_ID,
scanner.getPHPVersion()), pos);
ASTNode body = (ASTNode) event.getOriginalValue();
int bodyEnd = body.getStart() + body.getLength();
int endPos = getScanner().getTokenStartOffset(
SymbolsProvider.getSymbol(SymbolsProvider.WHILE_ID,
scanner.getPHPVersion()), bodyEnd);
rewriteBodyNode(node, DoStatement.BODY_PROPERTY, startOffset,
endPos, getIndent(node.getStart()),
this.formatter.DO_BLOCK); // body
} else {
voidVisit(node, DoStatement.BODY_PROPERTY);
}
} catch (CoreException e) {
handleException(e);
}
rewriteRequiredNode(node, DoStatement.CONDITION_PROPERTY);
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.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.jdt.core.dom.ASTVisitor#visit(ExpressionStatement)
*/
public boolean visit(ExpressionStatement node) { // expression
return rewriteRequiredNodeVisit(node,
ExpressionStatement.EXPRESSION_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(FieldAccess)
*/
public boolean visit(FieldAccess node) { // expression.name
return rewriteRequiredNodeVisit(node, FieldAccess.DISPATCHER_PROPERTY,
FieldAccess.FIELD_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(FieldDeclaration)
*/
public boolean visit(FieldsDeclaration node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteModifiers(node, FieldsDeclaration.MODIFIER_PROPERTY,
node.getStart());
rewriteNodeList(node, FieldsDeclaration.FIELDS_PROPERTY,
node.getStart() + node.getModifierString().length(), "", ", "); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.SingleFieldDeclaration)
*/
public boolean visit(SingleFieldDeclaration singleFieldDeclaration) {
if (!hasChildrenChanges(singleFieldDeclaration)) {
return doVisitUnchangedChildren(singleFieldDeclaration);
}
RewriteEvent event = getEvent(singleFieldDeclaration,
SingleFieldDeclaration.VALUE_PROPERTY);
if (event != null) {
rewriteOptionalValueProperty(singleFieldDeclaration,
singleFieldDeclaration.getName().getEnd(),
SingleFieldDeclaration.VALUE_PROPERTY, event);
}
return rewriteRequiredNodeVisit(singleFieldDeclaration,
SingleFieldDeclaration.NAME_PROPERTY);
}
/*
* Rewrite an optional value property. This should handle declarations like
* $a = 3 etc. and add, remove or modify the assigned value. Note that the
* new value that will be used must be an ASTNode, so in any other case
* where a value property does not hold an ASTNode this call will fail.
*
* @param node The node that we rewrite
*
* @param pos The position that the edit should start from
*
* @param valueProperty ChildPropertyDescriptor
*
* @param event Non-null RewriteEvent
*/
private void rewriteOptionalValueProperty(ASTNode node, int pos,
ChildPropertyDescriptor valueProperty, RewriteEvent event) {
TextEditGroup editGroup = getEditGroup(event);
int kind = event.getChangeKind();
switch (kind) {
case RewriteEvent.REPLACED:
rewriteRequiredNode(node, valueProperty);
break;
case RewriteEvent.INSERTED:
ASTNode newNode = (ASTNode) event.getNewValue();
doTextInsert(pos, " = ", editGroup); //$NON-NLS-1$
doTextInsert(pos, newNode, 0, false, editGroup);
break;
case RewriteEvent.REMOVED:
ASTNode originalNode = (ASTNode) event.getOriginalValue();
int endPos = originalNode.getEnd();
doTextRemove(pos, endPos - pos, editGroup);
break;
default:
// do nothing
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ForStatement)
*/
public boolean visit(ForStatement node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
try {
int pos = node.getStart();
if (isChanged(node, ForStatement.INITIALIZERS_PROPERTY)) {
// position after opening parent
int startOffset = getLeftParenthesesStartPosition(pos) + 1;
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
Symbol semicolonSym = SymbolsProvider.getSymbol(
SymbolsProvider.SEMICOLON_ID, scanner.getPHPVersion());
pos = getScanner().getTokenEndOffset(semicolonSym, pos);
pos = rewriteNodeList(node, ForStatement.EXPRESSION_PROPERTY, pos,
"", ", "); //$NON-NLS-1$ //$NON-NLS-2$
if (isChanged(node, ForStatement.UPDATERS_PROPERTY)) {
int startOffset = getScanner().getTokenEndOffset(semicolonSym,
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(
SymbolsProvider.getSymbol(SymbolsProvider.RPAREN_ID,
scanner.getPHPVersion()), pos);
rewriteBodyNode(node, ForStatement.BODY_PROPERTY, startOffset,
-1, getIndent(node.getStart()),
this.formatter.FOR_BLOCK); // body
} else {
voidVisit(node, ForStatement.BODY_PROPERTY);
}
} catch (CoreException e) {
handleException(e);
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(IfStatement)
*/
public boolean visit(IfStatement node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
int pos = rewriteRequiredNode(node, IfStatement.CONDITION_PROPERTY); // statement
RewriteEvent thenEvent = getEvent(node,
IfStatement.TRUE_STATEMENT_PROPERTY);
int elseChange = getChangeKind(node,
IfStatement.FALSE_STATEMENT_PROPERTY);
if (thenEvent != null
&& thenEvent.getChangeKind() != RewriteEvent.UNCHANGED) {
try {
pos = getScanner().getTokenEndOffset(
SymbolsProvider.getSymbol(SymbolsProvider.RPAREN_ID,
scanner.getPHPVersion()), pos); // after the
// closing
// parent
int indent = getIndent(node.getStart());
int endPos = -1;
Object elseStatement = getOriginalValue(node,
IfStatement.FALSE_STATEMENT_PROPERTY);
if (elseStatement != null) {
ASTNode thenStatement = (ASTNode) thenEvent
.getOriginalValue();
endPos = getScanner().getTokenStartOffset(
SymbolsProvider.getSymbol(SymbolsProvider.ELSE_ID,
scanner.getPHPVersion()),
thenStatement.getStart()
+ thenStatement.getLength()); // else
// keyword
}
if (elseStatement == null
|| elseChange != RewriteEvent.UNCHANGED) {
pos = rewriteBodyNode(node,
IfStatement.TRUE_STATEMENT_PROPERTY, pos, endPos,
indent, this.formatter.IF_BLOCK_NO_ELSE);
} else {
pos = rewriteBodyNode(node,
IfStatement.TRUE_STATEMENT_PROPERTY, pos, endPos,
indent, this.formatter.IF_BLOCK_WITH_ELSE);
}
} catch (CoreException e) {
handleException(e);
}
} else {
pos = doVisit(node, IfStatement.TRUE_STATEMENT_PROPERTY, pos);
}
if (elseChange != RewriteEvent.UNCHANGED) {
int indent = getIndent(node.getStart());
Object newThen = getNewValue(node,
IfStatement.TRUE_STATEMENT_PROPERTY);
if (newThen instanceof Block) {
rewriteBodyNode(node, IfStatement.FALSE_STATEMENT_PROPERTY,
pos, -1, indent, this.formatter.ELSE_AFTER_BLOCK);
} else {
rewriteBodyNode(node, IfStatement.FALSE_STATEMENT_PROPERTY,
pos, -1, indent, this.formatter.ELSE_AFTER_STATEMENT);
}
} else {
pos = doVisit(node, IfStatement.FALSE_STATEMENT_PROPERTY, pos);
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.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);
if (needsNewOperation) {
String operation = InfixExpression
.getOperator((Integer) getNewValue(node,
InfixExpression.OPERATOR_PROPERTY));
replaceOperation(pos, operation,
getEditGroup(node, InfixExpression.OPERATOR_PROPERTY));
}
pos = rewriteRequiredNode(node, InfixExpression.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.jdt.core.dom.ASTVisitor#visit(Javadoc)
// */
// public boolean visit(Javadoc node) {
// if (!hasChildrenChanges(node)) {
// return doVisitUnchangedChildren(node);
// }
// int startPos= node.getStart() + 3;
// String separator= getLineDelimiter() + getIndentAtOffset(node.getStart()) + " * "; //$NON-NLS-1$
//
// rewriteNodeList(node, Javadoc.TAGS_PROPERTY, startPos, separator,
// separator);
// return false;
// }
// /* (non-Javadoc)
// * @see org.eclipse.jdt.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.jdt.core.dom.ASTVisitor#visit(MethodInvocation)
*/
public boolean visit(MethodInvocation node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
int pos = rewriteOptionalQualifier(node,
MethodInvocation.DISPATCHER_PROPERTY, node.getStart());
// pos = rewriteRequiredNode(node, MethodInvocation.NAME_PROPERTY);
pos = rewriteRequiredNode(node, MethodInvocation.METHOD_PROPERTY);
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(PostfixExpression)
*/
public boolean visit(PostfixExpression node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
int pos = rewriteRequiredNode(node, PostfixExpression.VARIABLE_PROPERTY);
rewriteOperation(node, PostfixExpression.OPERATOR_PROPERTY, pos);
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(PrefixExpression)
*/
public boolean visit(PrefixExpression node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteOperation(node, PrefixExpression.OPERATOR_PROPERTY,
node.getStart());
rewriteRequiredNode(node, PrefixExpression.VARIABLE_PROPERTY);
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(SwitchCase)
*/
public boolean visit(SwitchCase node) {
// dont allow switching from case to default or back. New statements
// should be created.
if (isChanged(node, SwitchCase.ACTIONS_PROPERTY)) {
int pos = node.getStart();
ASTNode value = node.getValue();
if (value != null) {
int valueEnd = value.getEnd();
if (valueEnd > -1) {
pos = valueEnd;
}
}
rewriteNodeList(node, SwitchCase.ACTIONS_PROPERTY, pos, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
return rewriteRequiredNodeVisit(node, SwitchCase.VALUE_PROPERTY);
}
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.getType() != ASTNode.SWITCH_CASE) {
indent++;
}
return indent;
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(SwitchStatement)
*/
public boolean visit(SwitchStatement node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
int pos = rewriteRequiredNode(node, SwitchStatement.EXPRESSION_PROPERTY);
Block body = node.getBody();
ChildListPropertyDescriptor property = Block.STATEMENTS_PROPERTY;
if (getChangeKind(body, property) != RewriteEvent.UNCHANGED) {
try {
pos = getLeftBraceStartPosition(pos) + 1;
int insertIndent = getIndent(body.getStart()) + 1;
ParagraphListRewriter listRewriter = new SwitchListRewriter(
insertIndent);
StringBuffer leadString = new StringBuffer();
leadString.append(getLineDelimiter());
leadString.append(createIndentString(insertIndent));
listRewriter.rewriteList(body, property, pos,
leadString.toString());
} catch (CoreException e) {
handleException(e);
}
} else {
voidVisit(body, Block.STATEMENTS_PROPERTY);
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ThrowStatement)
*/
public boolean visit(ThrowStatement node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
try {
int offset = getScanner().getTokenEndOffset(
SymbolsProvider.getSymbol(SymbolsProvider.THROW_ID,
scanner.getPHPVersion()), node.getStart());
ensureSpaceBeforeReplace(node, ThrowStatement.EXPRESSION_PROPERTY,
offset, 0);
rewriteRequiredNode(node, ThrowStatement.EXPRESSION_PROPERTY);
} catch (CoreException e) {
handleException(e);
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.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.getStart());
// String prefix = this.formatter.CATCH_BLOCK.getPrefix(indent);
// TODO - Get the formatter prefix for the catch clause indentation
String prefix = ""; //$NON-NLS-1$
pos = rewriteNodeList(node, TryStatement.CATCH_CLAUSES_PROPERTY,
pos, prefix, prefix);
} else {
pos = doVisit(node, TryStatement.CATCH_CLAUSES_PROPERTY, pos);
}
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.core.dom.ASTVisitor#visit(WhileStatement)
*/
public boolean visit(WhileStatement node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
int pos = rewriteRequiredNode(node, WhileStatement.CONDITION_PROPERTY);
try {
if (isChanged(node, WhileStatement.BODY_PROPERTY)) {
int startOffset = getScanner().getTokenEndOffset(
SymbolsProvider.getSymbol(SymbolsProvider.RPAREN_ID,
scanner.getPHPVersion()), pos);
rewriteBodyNode(node, WhileStatement.BODY_PROPERTY,
startOffset, -1, getIndent(node.getStart()),
this.formatter.WHILE_BLOCK); // body
} else {
voidVisit(node, WhileStatement.BODY_PROPERTY);
}
} catch (CoreException e) {
handleException(e);
}
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;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.ArrayElement)
*/
public boolean visit(ArrayElement arrayElement) {
// Since the key property is optional, we need to treat it separately.
rewriteArrayElementKey(arrayElement);
return rewriteRequiredNodeVisit(arrayElement,
ArrayElement.VALUE_PROPERTY);
}
/*
* Rewrite the optional key part of the array element
*
* @param arrayElement
*/
private void rewriteArrayElementKey(ArrayElement arrayElement) {
RewriteEvent event = getEvent(arrayElement, ArrayElement.KEY_PROPERTY);
if (event != null) {
rewriteKeyValue(arrayElement, event);
}
}
/*
* Rewrite a key=>value pair
*
* @param arrayElement
*
* @param event
*/
private void rewriteKeyValue(ASTNode node, RewriteEvent event) {
int kind = event.getChangeKind();
TextEditGroup editGroup = getEditGroup(event);
switch (kind) {
case RewriteEvent.INSERTED:
// We should insert the key and the => string
Expression newValue = (Expression) event.getNewValue();
int start = node.getStart();
if (node instanceof ForEachStatement) {
start = ((ForEachStatement) node).getValue().getStart();
} else if (node instanceof YieldExpression) {
start = ((YieldExpression) node).getExpression().getStart();
}
doTextInsert(start, newValue, 0, false, editGroup);
doTextInsert(start, "=>", editGroup); //$NON-NLS-1$
break;
case RewriteEvent.REMOVED:
Expression removedExpression = (Expression) event
.getOriginalValue();
int deleteEndPos = -1;
if (node instanceof ArrayElement) {
deleteEndPos = ((ArrayElement) node).getValue().getStart();
} else if (node instanceof ForEachStatement) {
deleteEndPos = ((ForEachStatement) node).getValue().getStart();
} else if (node instanceof YieldExpression) {
deleteEndPos = ((YieldExpression) node).getExpression()
.getStart();
}
int deleteStartPos = removedExpression.getStart();
doTextRemove(deleteStartPos, deleteEndPos - deleteStartPos,
editGroup);
break;
case RewriteEvent.REPLACED:
if (node instanceof ArrayElement) {
rewriteRequiredNode(node, ArrayElement.KEY_PROPERTY);
} else if (node instanceof ForEachStatement) {
rewriteRequiredNode(node, ForEachStatement.KEY_PROPERTY);
} else if (node instanceof YieldExpression) {
rewriteRequiredNode(node, YieldExpression.KEY_PROPERTY);
}
break;
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.ASTError)
*/
@Override
public boolean visit(ASTError astError) {
if (!hasChildrenChanges(astError)) {
return doVisitUnchangedChildren(astError);
}
changeNotSupported(astError); // no modification possible
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.BackTickExpression)
*/
public boolean visit(BackTickExpression backTickExpression) {
if (!hasChildrenChanges(backTickExpression)) {
return doVisitUnchangedChildren(backTickExpression);
}
rewriteNodeList(backTickExpression,
BackTickExpression.EXPRESSIONS_PROPERTY,
backTickExpression.getStart(), "", ""); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.ClassConstantDeclaration)
*/
@Override
public boolean visit(ConstantDeclaration classConstantDeclaration) {
// TODO - Same as with the DeclareStatement, this require a different
// rewriting for now.
if (!hasChildrenChanges(classConstantDeclaration)) {
return doVisitUnchangedChildren(classConstantDeclaration);
}
changeNotSupported(classConstantDeclaration);
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.ClassDeclaration)
*/
@Override
public boolean visit(ClassDeclaration classDeclaration) {
if (!hasChildrenChanges(classDeclaration)) {
return doVisitUnchangedChildren(classDeclaration);
}
try {
// Rewrite the modifier property
rewriteClassDeclarationModifier(classDeclaration);
// Rewrite the super-class property
rewriteClassDeclarationSuperClass(classDeclaration);
// Rewrite the interfaces
int pos;
if (classDeclaration.getSuperClass() == null) {
pos = classDeclaration.getName().getEnd();
} else {
pos = classDeclaration.getSuperClass().getEnd();
}
rewriteNodeList(classDeclaration,
ClassDeclaration.INTERFACES_PROPERTY, pos, " implements ", //$NON-NLS-1$
", "); //$NON-NLS-1$
// Rewrite the name and the body
return rewriteRequiredNodeVisit(classDeclaration,
ClassDeclaration.NAME_PROPERTY,
ClassDeclaration.BODY_PROPERTY);
} catch (Exception e) {
handleException(e);
}
return false;
}
/*
* Rewrite the modifier part of the class declaration
*
* @param classDeclaration
*/
private void rewriteClassDeclarationModifier(
ClassDeclaration classDeclaration) throws CoreException {
RewriteEvent event = getEvent(classDeclaration,
ClassDeclaration.MODIFIER_PROPERTY);
if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) {
TextEditGroup editGroup = getEditGroup(event);
int start = classDeclaration.getStart();
int classKeywordStart = getScanner().getTokenStartOffset(
SymbolsProvider.getSymbol(SymbolsProvider.CLASS_ID,
scanner.getPHPVersion()), start);
int modifier = (Integer) event.getNewValue();
switch (modifier) {
case ClassDeclaration.MODIFIER_NONE:
// The modifier was removed
doTextRemove(start, classKeywordStart - start, editGroup);
break;
case ClassDeclaration.MODIFIER_ABSTRACT:
case ClassDeclaration.MODIFIER_FINAL:
// Replace what we have (if we have it) with the 'abstract' or
// the 'final' keyword
doTextReplace(start, classKeywordStart - start,
ClassDeclaration.getModifier(modifier) + ' ', editGroup);
break;
}
}
}
/*
* Rewrite the super-class part of the class declaration
*
* @param classDeclaration
*/
private void rewriteClassDeclarationSuperClass(
ClassDeclaration classDeclaration) throws CoreException {
RewriteEvent event = getEvent(classDeclaration,
ClassDeclaration.SUPER_CLASS_PROPERTY);
if (event != null) {
int changeKind = event.getChangeKind();
TextEditGroup editGroup = getEditGroup(event);
switch (changeKind) {
case RewriteEvent.INSERTED:
Identifier superClass = (Identifier) event.getNewValue();
int insertionPos = classDeclaration.getName().getEnd();
String extendsKeyword = " extends "; //$NON-NLS-1$
doTextInsert(insertionPos, extendsKeyword, editGroup);
doTextInsert(insertionPos, superClass, 0, false, editGroup);
break;
case RewriteEvent.REMOVED:
superClass = (Identifier) event.getOriginalValue();
// locate the end offset of the deletion
int deletionEnd;
if (classDeclaration.interfaces().size() > 0) {
deletionEnd = getScanner().getTokenStartOffset(
SymbolsProvider.getSymbol(
SymbolsProvider.IMPLEMENTS_ID,
scanner.getPHPVersion()),
classDeclaration.getStart());
} else {
deletionEnd = classDeclaration.getBody().getStart();
}
int deletionStart = classDeclaration.getName().getEnd();
doTextRemove(deletionStart, deletionEnd - deletionStart,
editGroup);
doTextInsert(deletionStart, " ", editGroup); //$NON-NLS-1$
break;
case RewriteEvent.REPLACED:
rewriteRequiredNode(classDeclaration,
ClassDeclaration.SUPER_CLASS_PROPERTY);
break;
}
}
}
/**
* Rewrite the interfaces in the class declaration
*
* @param classDeclaration
*/
private void rewriteInterfaces(ClassDeclaration classDeclaration) {
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.ClassName)
*/
public boolean visit(ClassName className) {
return rewriteRequiredNodeVisit(className, ClassName.NAME_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.CloneExpression)
*/
public boolean visit(CloneExpression cloneExpression) {
return rewriteRequiredNodeVisit(cloneExpression,
CloneExpression.EXPRESSION_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.Comment)
*/
@Override
public boolean visit(Comment comment) {
// TODO Auto-generated method stub
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.DeclareStatement)
*/
@Override
public boolean visit(DeclareStatement declareStatement) {
// TODO - This require a different rewrite approach since a regular list
// rewrite will not work here when adding and removing items
if (!hasChildrenChanges(declareStatement)) {
return doVisitUnchangedChildren(declareStatement);
}
changeNotSupported(declareStatement);
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.EchoStatement)
*/
public boolean visit(EchoStatement echoStatement) {
if (!hasChildrenChanges(echoStatement)) {
return doVisitUnchangedChildren(echoStatement);
}
rewriteNodeList(echoStatement, EchoStatement.EXPRESSIONS_PROPERTY,
echoStatement.getStart(), "", ", "); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.ForEachStatement)
*/
@Override
public boolean visit(ForEachStatement forEachStatement) {
if (!hasChildrenChanges(forEachStatement)) {
return doVisitUnchangedChildren(forEachStatement);
}
RewriteEvent event = getEvent(forEachStatement,
ForEachStatement.KEY_PROPERTY);
if (event != null) {
rewriteKeyValue(forEachStatement, event);
}
rewriteRequiredNodeVisit(forEachStatement,
ForEachStatement.EXPRESSION_PROPERTY,
ForEachStatement.VALUE_PROPERTY,
ForEachStatement.STATEMENT_PROPERTY);
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.FormalParameter)
*/
public boolean visit(FormalParameter formalParameter) {
try {
if (formalParameter.getAST().apiLevel() == PHPVersion.PHP4
&& isChanged(formalParameter,
FormalParameter.IS_MANDATORY_PROPERTY)) {
if (formalParameter.getAST().apiLevel() == PHPVersion.PHP5) {
throw new CoreException(
new Status(IStatus.ERROR, PHPCorePlugin.ID,
"Could not set a FormalParameter 'isMandatory' property for PHP5 AST")); //$NON-NLS-1$
}
// Rewrite the isMandatory field
RewriteEvent event = getEvent(formalParameter,
FormalParameter.IS_MANDATORY_PROPERTY);
if (event != null
&& event.getChangeKind() == RewriteEvent.REPLACED) {
TextEditGroup editGroup = getEditGroup(event);
boolean isMandatory = (Boolean) event.getNewValue();
if (isMandatory) {
// remove the const from the start of the parameter (6
// characters including the space)
doTextRemove(formalParameter.getStart(), 6, editGroup);
} else {
doTextInsert(formalParameter.getStart(), "const ", //$NON-NLS-1$
editGroup);
}
}
}
} catch (Exception e) {
handleException(e);
}
// Rewrite the parameter type
rewriteFormalParameterType(formalParameter);
// Rewrite the default parameters
rewriteFomalParameterDefault(formalParameter);
return rewriteRequiredNodeVisit(formalParameter,
FormalParameter.PARAMETER_NAME_PROPERTY);
}
/*
* Rewrite the parameter type of a {@link FormalParameter}
*
* @param formalParameter
*/
private void rewriteFormalParameterType(FormalParameter formalParameter) {
// Rewrite the parameter type
RewriteEvent event = getEvent(formalParameter,
FormalParameter.PARAMETER_TYPE_PROPERTY);
if (event != null) {
int kind = event.getChangeKind();
switch (kind) {
case RewriteEvent.REPLACED:
int pos = rewriteRequiredNode(formalParameter,
FormalParameter.PARAMETER_TYPE_PROPERTY);
ASTNode originalValue = (ASTNode) event.getOriginalValue();
if (originalValue == null || originalValue.getLength() == 0) {
// Add another space to split the type from the name
doTextInsert(pos, " ", getEditGroup(event)); //$NON-NLS-1$
}
break;
case RewriteEvent.INSERTED:
Identifier identifier = (Identifier) event.getNewValue();
String name = identifier.getName();
if (name != null) {
if (!name.endsWith(" ") && !name.endsWith("\t")) { //$NON-NLS-1$ //$NON-NLS-2$
name += ' ';
}
doTextInsert(formalParameter.getStart(), name,
getEditGroup(event));
}
break;
case RewriteEvent.REMOVED:
originalValue = (ASTNode) event.getOriginalValue();
doTextRemove(originalValue.getStart(),
originalValue.getLength(), getEditGroup(event));
break;
}
}
}
/*
* Rewrite the parameter's default value of a {@link FormalParameter}
*
* @param formalParameter
*/
private void rewriteFomalParameterDefault(FormalParameter formalParameter) {
RewriteEvent event = getEvent(formalParameter,
FormalParameter.DEFAULT_VALUE_PROPERTY);
if (event != null) {
int kind = event.getChangeKind();
switch (kind) {
case RewriteEvent.REPLACED:
rewriteRequiredNode(formalParameter,
FormalParameter.DEFAULT_VALUE_PROPERTY);
break;
case RewriteEvent.INSERTED:
Scalar scalar = (Scalar) event.getNewValue();
String scalarValue = scalar.getStringValue();
if (scalar != null) {
doTextInsert(formalParameter.getStart(), " = " //$NON-NLS-1$
+ scalarValue, getEditGroup(event));
}
break;
case RewriteEvent.REMOVED:
ASTNode originalValue = (ASTNode) event.getOriginalValue();
int nameEnd = formalParameter.getParameterName().getEnd();
doTextRemove(nameEnd, originalValue.getEnd() - nameEnd,
getEditGroup(event));
break;
}
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.FunctionDeclaration)
*/
public boolean visit(FunctionDeclaration functionDeclaration) {
if (!hasChildrenChanges(functionDeclaration)) {
return doVisitUnchangedChildren(functionDeclaration);
}
// Reference
rewriteFunctionReference(functionDeclaration);
// Name
int pos = rewriteRequiredNode(functionDeclaration,
FunctionDeclaration.NAME_PROPERTY);
// Parameters
if (isChanged(functionDeclaration,
FunctionDeclaration.FORMAL_PARAMETERS_PROPERTY)) {
try {
int startOffset = getLeftParenthesesStartPosition(pos) + 1;
rewriteNodeList(functionDeclaration,
FunctionDeclaration.FORMAL_PARAMETERS_PROPERTY,
startOffset, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$
} catch (CoreException e) {
handleException(e);
}
} else {
voidVisit(functionDeclaration,
FunctionDeclaration.FORMAL_PARAMETERS_PROPERTY);
}
// Body
rewriteRequiredNode(functionDeclaration,
FunctionDeclaration.BODY_PROPERTY);
return false;
}
private void rewriteFunctionReference(
FunctionDeclaration functionDeclaration) {
RewriteEvent event = getEvent(functionDeclaration,
FunctionDeclaration.IS_REFERENCE_PROPERTY);
if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) {
boolean isReference = (Boolean) event.getNewValue();
TextEditGroup editGroup = getEditGroup(event);
// we need to remove everything between the word 'function' to the
// start of the function's
// name and then place a blank or an &.
int nameStart = functionDeclaration.getFunctionName().getStart();
int startDeletionFrom = functionDeclaration.getStart() + 8; // 8 is
// the
// 'function'
// keyword
// length
doTextRemove(startDeletionFrom, nameStart - startDeletionFrom,
editGroup);
if (isReference) {
// we need to insert the &
doTextInsert(startDeletionFrom, " &", editGroup); //$NON-NLS-1$
} else {
doTextInsert(startDeletionFrom, " ", editGroup); //$NON-NLS-1$
}
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.FunctionInvocation)
*/
public boolean visit(FunctionInvocation functionInvocation) {
if (!hasChildrenChanges(functionInvocation)) {
return doVisitUnchangedChildren(functionInvocation);
}
int pos = rewriteRequiredNode(functionInvocation,
FunctionInvocation.FUNCTION_PROPERTY);
if (isChanged(functionInvocation,
FunctionInvocation.PARAMETERS_PROPERTY)) {
// eval position after opening parent
try {
int startOffset = getLeftParenthesesStartPosition(pos) + 1;
rewriteNodeList(functionInvocation,
FunctionInvocation.PARAMETERS_PROPERTY, startOffset,
"", ", "); //$NON-NLS-1$ //$NON-NLS-2$
} catch (CoreException e) {
handleException(e);
}
} else {
voidVisit(functionInvocation,
FunctionInvocation.PARAMETERS_PROPERTY);
}
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.FunctionName)
*/
public boolean visit(FunctionName functionName) {
return rewriteRequiredNodeVisit(functionName,
FunctionName.NAME_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.GlobalStatement)
*/
public boolean visit(GlobalStatement globalStatement) {
if (!hasChildrenChanges(globalStatement)) {
return doVisitUnchangedChildren(globalStatement);
}
rewriteNodeList(globalStatement, GlobalStatement.VARIABLES_PROPERTY,
globalStatement.getStart(), "", ", "); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.Identifier)
*/
public boolean visit(Identifier node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
String newString = (String) getNewValue(node, Identifier.NAME_PROPERTY);
TextEditGroup group = getEditGroup(node, Identifier.NAME_PROPERTY);
doTextReplace(node.getStart(), node.getLength(), newString, group);
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.IgnoreError)
*/
public boolean visit(IgnoreError ignoreError) {
return rewriteRequiredNodeVisit(ignoreError,
IgnoreError.EXPRESSION_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.Include)
*/
public boolean visit(Include include) {
if (!hasChildrenChanges(include)) {
return doVisitUnchangedChildren(include);
}
int offsetGap = 0;
if (isChanged(include, Include.INCLUDE_TYPE_PROPERTY)) {
RewriteEvent event = getEvent(include,
Include.INCLUDE_TYPE_PROPERTY);
if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) {
TextEditGroup editGroup = getEditGroup(event);
int newValue = (Integer) event.getNewValue();
int originalTypeLength = Include.getType(
(Integer) event.getOriginalValue()).length();
String newIncludeType = Include.getType(newValue);
doTextReplace(include.getStart(), originalTypeLength,
newIncludeType, editGroup);
offsetGap = originalTypeLength - newIncludeType.length();
}
}
if (isChanged(include, Include.EXPRESSION_PROPERTY)) {
// This should be treated specially in case that the new expression
// removes the parentheses of the
// include.
// In this situation, we might get a syntax error, so we have to
// deal with it here.
RewriteEvent event = getEvent(include, Include.EXPRESSION_PROPERTY);
if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) {
TextEditGroup editGroup = getEditGroup(event);
int typeEndOffset = Include.getType(include.getIncludeType())
.length() + include.getStart();
ASTNode newNode = (ASTNode) event.getNewValue();
ASTNode originalNode = (ASTNode) event.getOriginalValue();
// In case that the offset of the original node started right at
// the end of the include string, check that
// the new node is not a parenthesis, and if not - add a blank
if (typeEndOffset + offsetGap == originalNode.getStart()
&& newNode.getType() != ASTNode.PARENTHESIS_EXPRESSION) {
doTextInsert(offsetGap + typeEndOffset, " ", editGroup); //$NON-NLS-1$
rewriteRequiredNode(include, Include.EXPRESSION_PROPERTY);
} else {
rewriteRequiredNode(include, Include.EXPRESSION_PROPERTY);
}
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.InLineHtml)
*/
@Override
public boolean visit(InLineHtml inLineHtml) {
if (!hasChildrenChanges(inLineHtml)) {
return doVisitUnchangedChildren(inLineHtml);
}
changeNotSupported(inLineHtml); // no modification possible
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.InstanceOfExpression)
*/
public boolean visit(InstanceOfExpression instanceOfExpression) {
return rewriteRequiredNodeVisit(instanceOfExpression,
InstanceOfExpression.CLASSNAME_PROPERTY,
InstanceOfExpression.EXPRESSION_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.InterfaceDeclaration)
*/
@Override
public boolean visit(InterfaceDeclaration interfaceDeclaration) {
if (!hasChildrenChanges(interfaceDeclaration)) {
return doVisitUnchangedChildren(interfaceDeclaration);
}
try {
// Rewrite the extended interfaces
rewriteNodeList(interfaceDeclaration,
InterfaceDeclaration.INTERFACES_PROPERTY,
interfaceDeclaration.getName().getEnd(), " extends ", ", "); //$NON-NLS-1$ //$NON-NLS-2$
// Rewrite the name and the body
return rewriteRequiredNodeVisit(interfaceDeclaration,
InterfaceDeclaration.NAME_PROPERTY,
InterfaceDeclaration.BODY_PROPERTY);
} catch (Exception e) {
handleException(e);
}
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.ListVariable)
*/
public boolean visit(ListVariable listVariable) {
if (!hasChildrenChanges(listVariable)) {
return doVisitUnchangedChildren(listVariable);
}
rewriteNodeList(listVariable, ListVariable.VARIABLES_PROPERTY,
listVariable.getStart(), "", ","); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.ParenthesisExpression)
*/
public boolean visit(ParenthesisExpression parenthesisExpression) {
return rewriteRequiredNodeVisit(parenthesisExpression,
ParenthesisExpression.EXPRESSION_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.Quote)
*/
public boolean visit(Quote quote) {
// Rewrite the quoate's type
rewriteQuoteType(quote);
// Rewrite the quoate's expressions list
rewriteQuoteExpression(quote);
return false;
}
/**
* @param quote
*/
private void rewriteQuoteExpression(Quote quote) {
int expressionStart = quote.getStart();
switch (quote.getQuoteType()) {
case Quote.QT_QUOTE:
case Quote.QT_SINGLE:
expressionStart++;
break;
case Quote.QT_HEREDOC:
// search for the first new line
int quoteEnd = quote.getEnd();
for (; expressionStart < quoteEnd; expressionStart++) {
if (content[expressionStart] == '\n'
|| content[expressionStart] == '\r') {
expressionStart++;
if (content[expressionStart] == '\n'
|| content[expressionStart] == '\r') {
expressionStart++;
}
break;
}
}
break;
}
rewriteNodeList(quote, Quote.EXPRESSIONS_PROPERTY, expressionStart, "", //$NON-NLS-1$
""); //$NON-NLS-1$
// In case that the original expressions list was empty, we should add a
// new line
List originalValue = (List) getOriginalValue(quote,
Quote.EXPRESSIONS_PROPERTY);
List newValue = (List) getNewValue(quote, Quote.EXPRESSIONS_PROPERTY);
if ((originalValue == null || originalValue.size() == 0)
&& newValue != null && newValue.size() > 0) {
doTextInsert(expressionStart, "\n", //$NON-NLS-1$
getEditGroup(quote, Quote.EXPRESSIONS_PROPERTY));
}
}
/**
* @param quote
*/
private void rewriteQuoteType(Quote quote) {
if (isChanged(quote, Quote.QUOTE_TYPE_PROPERTY)) {
List<Expression> expressions = quote.expressions();
if (expressions.size() > 0) {
RewriteEvent event = getEvent(quote, Quote.QUOTE_TYPE_PROPERTY);
if (event != null
&& event.getChangeKind() == RewriteEvent.REPLACED) {
TextEditGroup editGroup = getEditGroup(event);
int expressionsStart = expressions.get(0).getStart();
int expressionsEnd = expressions
.get(expressions.size() - 1).getEnd();
int quoteStart = quote.getStart();
int quoteEnd = quote.getEnd();
// In case this is a Heredoc, we need to fix the expression
// end position to exclude the heredoc marker.
int originalType = (Integer) event.getOriginalValue();
if (originalType == Quote.QT_HEREDOC) {
for (; expressionsEnd > expressionsStart; expressionsEnd--) {
if (content[expressionsEnd] == '\n'
|| content[expressionsEnd] == '\r') {
// Check that we don't have a pair of \n\r
// before we break the loop
if (content[expressionsEnd - 1] == '\n'
|| content[expressionsEnd - 1] == '\r') {
expressionsEnd--;
}
break;
}
}
}
int newType = (Integer) event.getNewValue();
String newStart = ""; //$NON-NLS-1$
String newEnd = ""; //$NON-NLS-1$
switch (newType) {
case Quote.QT_SINGLE:
newStart = "'"; //$NON-NLS-1$
newEnd = "'"; //$NON-NLS-1$
break;
case Quote.QT_QUOTE:
newStart = "\""; //$NON-NLS-1$
newEnd = "\""; //$NON-NLS-1$
break;
case Quote.QT_NOWDOC:
newStart = "<<<'Heredoc'\n"; //$NON-NLS-1$
newEnd = "\nHeredoc;\n"; //$NON-NLS-1$
break;
case Quote.QT_HEREDOC:
newStart = "<<<Heredoc\n"; //$NON-NLS-1$
newEnd = "\nHeredoc;\n"; //$NON-NLS-1$
break;
}
doTextReplace(quoteStart, expressionsStart - quoteStart,
newStart, editGroup);
doTextReplace(expressionsEnd, quoteEnd - expressionsEnd,
newEnd, editGroup);
}
}
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.Reference)
*/
public boolean visit(Reference reference) {
return rewriteRequiredNodeVisit(reference,
Reference.EXPRESSION_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.ReflectionVariable)
*/
public boolean visit(ReflectionVariable reflectionVariable) {
if (isChanged(reflectionVariable, ReflectionVariable.DOLLARED_PROPERTY)) {
rewriteVariableDollar(reflectionVariable);
}
return rewriteRequiredNodeVisit(reflectionVariable,
ReflectionVariable.NAME_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.Scalar)
*/
public boolean visit(Scalar scalar) {
// For now, we ignore the Scalar.TYPE_PROPERTY changes and we only deal
// with the value property of the scalar.
RewriteEvent event = getEvent(scalar, Scalar.VALUE_PROPERTY);
if (event != null) {
String newValue = (String) event.getNewValue();
if (newValue == null) {
newValue = ""; //$NON-NLS-1$
}
int kind = event.getChangeKind();
switch (kind) {
case RewriteEvent.REPLACED:
doTextReplace(scalar.getStart(), scalar.getLength(), newValue,
getEditGroup(event));
break;
case RewriteEvent.INSERTED:
doTextInsert(scalar.getStart(), newValue, getEditGroup(event));
break;
case RewriteEvent.REMOVED:
doTextRemove(scalar.getStart(), scalar.getLength(),
getEditGroup(event));
break;
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.StaticConstantAccess)
*/
public boolean visit(StaticConstantAccess classConstantAccess) {
return rewriteRequiredNodeVisit(classConstantAccess,
StaticConstantAccess.CLASS_NAME_PROPERTY,
StaticConstantAccess.CONSTANT_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.StaticFieldAccess)
*/
public boolean visit(StaticFieldAccess staticFieldAccess) {
return rewriteRequiredNodeVisit(staticFieldAccess,
StaticFieldAccess.CLASS_NAME_PROPERTY,
StaticFieldAccess.FIELD_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.StaticMethodInvocation)
*/
public boolean visit(StaticMethodInvocation staticMethodInvocation) {
return rewriteRequiredNodeVisit(staticMethodInvocation,
StaticMethodInvocation.CLASS_NAME_PROPERTY,
StaticMethodInvocation.METHOD_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.StaticStatement)
*/
public boolean visit(StaticStatement staticStatement) {
if (!hasChildrenChanges(staticStatement)) {
return doVisitUnchangedChildren(staticStatement);
}
rewriteNodeList(staticStatement, StaticStatement.EXPRESSIONS_PROPERTY,
staticStatement.getStart(), "", ", "); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.UnaryOperation)
*/
public boolean visit(UnaryOperation unaryOperation) {
rewriteOperation(unaryOperation, UnaryOperation.OPERATOR_PROPERTY,
unaryOperation.getStart());
return rewriteRequiredNodeVisit(unaryOperation,
UnaryOperation.EXPRESSION_PROPERTY);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.internal.core.ast.visitor.AbstractVisitor#visit(org.eclipse
* .php.internal.core.ast.nodes.Variable)
*/
public boolean visit(Variable variable) {
if (isChanged(variable, Variable.DOLLARED_PROPERTY)) {
rewriteVariableDollar(variable);
}
return rewriteRequiredNodeVisit(variable, Variable.NAME_PROPERTY);
}
public boolean visit(GotoLabel gotoLabel) {
return rewriteRequiredNodeVisit(gotoLabel, GotoLabel.NAME_PROPERTY);
}
public boolean visit(GotoStatement gotoStatement) {
return rewriteRequiredNodeVisit(gotoStatement,
GotoStatement.LABEL_PROPERTY);
}
public boolean visit(LambdaFunctionDeclaration lambdaFunctionDeclaration) {
if (!hasChildrenChanges(lambdaFunctionDeclaration)) {
return doVisitUnchangedChildren(lambdaFunctionDeclaration);
}
// static FIXME
// RewriteEvent staticEvent = getEvent(lambdaFunctionDeclaration,
// LambdaFunctionDeclaration.IS_STATIC);
// if (staticEvent != null && staticEvent.getChangeKind() ==
// RewriteEvent.REPLACED) {
// boolean isStatic = (Boolean) staticEvent.getNewValue();
//
// try {
// TextEditGroup editGroup = getEditGroup(staticEvent);
// int startDeletionFrom = lambdaFunctionDeclaration.getStart() + 8;
// int startOffset = getLeftParenthesesStartPosition(startDeletionFrom);
// doTextRemove(startDeletionFrom,
// startOffset - startDeletionFrom, editGroup);
// if (isStatic) {
// doTextInsert(startDeletionFrom, " & ", editGroup);
// } else {
// doTextInsert(startDeletionFrom, " ", editGroup);
// }
// } catch (CoreException e) {
// handleException(e);
// }
// }
// Reference
RewriteEvent event = getEvent(lambdaFunctionDeclaration,
LambdaFunctionDeclaration.IS_REFERENCE_PROPERTY);
if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) {
boolean isReference = (Boolean) event.getNewValue();
try {
TextEditGroup editGroup = getEditGroup(event);
// we need to remove everything between the word 'function' to
// the start of the function's
// name and then place a blank or an &.
int startDeletionFrom = lambdaFunctionDeclaration.getStart() + 8; // 8
// is
// the
// 'function'
// keyword
// length
int startOffset = getLeftParenthesesStartPosition(startDeletionFrom);
doTextRemove(startDeletionFrom,
startOffset - startDeletionFrom, editGroup);
if (isReference) {
// we need to insert the &
doTextInsert(startDeletionFrom, " & ", editGroup); //$NON-NLS-1$
} else {
doTextInsert(startDeletionFrom, " ", editGroup); //$NON-NLS-1$
}
} catch (CoreException e) {
handleException(e);
}
}
// Parameters
if (isChanged(lambdaFunctionDeclaration,
LambdaFunctionDeclaration.FORMAL_PARAMETERS_PROPERTY)) {
try {
int startDeletionFrom = lambdaFunctionDeclaration.getStart() + 8; // 8
// is
// the
// 'function'
// keyword
// length
int startOffset = getLeftParenthesesStartPosition(startDeletionFrom);
rewriteNodeList(lambdaFunctionDeclaration,
LambdaFunctionDeclaration.FORMAL_PARAMETERS_PROPERTY,
startOffset, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$
} catch (CoreException e) {
handleException(e);
}
} else {
voidVisit(lambdaFunctionDeclaration,
LambdaFunctionDeclaration.FORMAL_PARAMETERS_PROPERTY);
}
// Lexical vars
if (isChanged(lambdaFunctionDeclaration,
LambdaFunctionDeclaration.LEXICAL_VARIABLES_PROPERTY)) {
try {
int startDeletionFrom = lambdaFunctionDeclaration.getStart() + 8; // 8
// is
// the
// 'function'
// keyword
// length
int startOffset = getRightBraceStartPosition(startDeletionFrom) + 1;
rewriteNodeList(lambdaFunctionDeclaration,
LambdaFunctionDeclaration.LEXICAL_VARIABLES_PROPERTY,
startOffset, " as ", ", "); //$NON-NLS-1$ //$NON-NLS-2$
} catch (CoreException e) {
handleException(e);
}
} else {
voidVisit(lambdaFunctionDeclaration,
LambdaFunctionDeclaration.LEXICAL_VARIABLES_PROPERTY);
}
// Body
rewriteRequiredNode(lambdaFunctionDeclaration,
LambdaFunctionDeclaration.BODY_PROPERTY);
return false;
}
public boolean visit(NamespaceDeclaration namespaceDeclaration) {
return rewriteRequiredNodeVisit(namespaceDeclaration,
NamespaceDeclaration.NAME_PROPERTY,
NamespaceDeclaration.BODY_PROPERTY);
}
public boolean visit(NamespaceName namespaceName) {
// Make the necessary changes to add or remove the '\' and 'namespace'
// prefixes
RewriteEvent event = getEvent(namespaceName,
NamespaceName.GLOBAL_PROPERTY);
if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) {
TextEditGroup editGroup = getEditGroup(event);
if ((Boolean) event.getNewValue()) {
// Add the '\' to the namespace name
this.doTextInsert(namespaceName.getStart(), "\\", editGroup); //$NON-NLS-1$
} else {
// Remove the '\' from the namespace name
this.doTextRemove(namespaceName.getStart(), 1, editGroup);
}
}
event = getEvent(namespaceName, NamespaceName.CURRENT_PROPERTY);
if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) {
TextEditGroup editGroup = getEditGroup(event);
if ((Boolean) event.getNewValue()) {
// Add the 'namespace' to the namespace name
this.doTextInsert(namespaceName.getStart(), "namespace\\", //$NON-NLS-1$
editGroup);
} else {
// Remove the 'namespace' from the namespace name
this.doTextRemove(namespaceName.getStart(), 10, editGroup);
}
}
int pos = namespaceName.getStart();
if (namespaceName.isGlobal()) {
pos += 1;
}
if (namespaceName.isCurrent()) {
pos += 10;
}
if (isChanged(namespaceName, NamespaceName.ELEMENTS_PROPERTY)) {
rewriteNodeList(namespaceName, NamespaceName.ELEMENTS_PROPERTY,
pos, "", "\\"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
voidVisit(namespaceName, NamespaceName.ELEMENTS_PROPERTY);
}
return false;
}
public boolean visit(UseStatement useStatement) {
rewriteNodeList(useStatement, UseStatement.PARTS_PROPERTY,
useStatement.getStart(), "", ", "); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
public boolean visit(UseStatementPart useStatementPart) {
return rewriteRequiredNodeVisit(useStatementPart,
UseStatementPart.NAME_PROPERTY, UseStatementPart.ALIAS_PROPERTY);
}
/**
* A general visit implementations that calls
* {@link #doVisitUnchangedChildren(ASTNode)} in case that the node has no
* changes in its children, and calls
* {@link #rewriteRequiredNode(ASTNode, StructuralPropertyDescriptor)} on
* the given {@link StructuralPropertyDescriptor} properties. The given
* property descriptors should be only {@link ChildPropertyDescriptor} and
* {@link SimplePropertyDescriptor}. In any other case,
* {@link #rewriteNodeList(ASTNode, StructuralPropertyDescriptor, int, String, String)}
* might be needed.
*
* @param node
* An {@link ASTNode}.
* @param properties
* StructuralPropertyDescriptors of the types
* {@link ChildPropertyDescriptor} and
* {@link SimplePropertyDescriptor}.
* @return false by default
*/
protected boolean rewriteRequiredNodeVisit(ASTNode node,
StructuralPropertyDescriptor... properties) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
for (StructuralPropertyDescriptor property : properties) {
rewriteRequiredNode(node, property);
}
return false;
}
// php5.4 starts
public boolean visit(ChainingInstanceCall node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteRequiredNode(node, ChainingInstanceCall.ARRAY_DEREFERENCE_LIST);
// rewriteNodeList(node,
// ChainingInstanceCall.CHAINING_METHOD_OR_PROPERTY,
// node.getStart(), "", "");
return false;
}
public boolean visit(DereferenceNode node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteRequiredNode(node, ChainingInstanceCall.ARRAY_DEREFERENCE_LIST);
return false;
}
public boolean visit(FullyQualifiedTraitMethodReference node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteRequiredNode(node, FullyQualifiedTraitMethodReference.CLASS_NAME);
rewriteRequiredNode(node,
FullyQualifiedTraitMethodReference.FUNCTION_NAME);
return false;
}
public boolean visit(PHPArrayDereferenceList node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteNodeList(node, PHPArrayDereferenceList.DEREFERENCES_PROPERTY,
node.getStart(), "", ""); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
public boolean visit(TraitAlias node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteRequiredNode(node, TraitAlias.TRAIT_METHOD);
rewriteModifiers(node, TraitAlias.MODIFIER, node.getModifierOffset());
rewriteRequiredNode(node, TraitAlias.FUNCTION_NAME);
return false;
}
public boolean visit(TraitAliasStatement node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteRequiredNode(node, TraitAliasStatement.EXP);
return false;
}
public boolean visit(TraitDeclaration node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
try {
// Rewrite the modifier property
// rewriteClassDeclarationModifier(classDeclaration);
// Rewrite the super-class property
// rewriteClassDeclarationSuperClass(classDeclaration);
// Rewrite the interfaces
// int pos;
// if (classDeclaration.getSuperClass() == null) {
// pos = classDeclaration.getName().getEnd();
// } else {
// pos = classDeclaration.getSuperClass().getEnd();
// }
// rewriteNodeList(classDeclaration,
// ClassDeclaration.INTERFACES_PROPERTY, pos, " implements ",
// ", ");
// Rewrite the name and the body
return rewriteRequiredNodeVisit(node,
ClassDeclaration.NAME_PROPERTY,
ClassDeclaration.BODY_PROPERTY);
} catch (Exception e) {
handleException(e);
}
return false;
}
public boolean visit(TraitPrecedence node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteRequiredNode(node, TraitPrecedence.METHOD_REFERENCE);
rewriteNodeList(node, TraitPrecedence.TRAIT_REFERENCE_LIST,
node.getStart(), "", ", "); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
public boolean visit(TraitPrecedenceStatement node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteRequiredNode(node, TraitPrecedenceStatement.EXP);
return false;
}
public boolean visit(TraitUseStatement node) {
if (!hasChildrenChanges(node)) {
return doVisitUnchangedChildren(node);
}
rewriteNodeList(node, TraitUseStatement.TRAIT, node.getStart(), "", //$NON-NLS-1$
", "); //$NON-NLS-1$
rewriteNodeList(node, TraitUseStatement.TRAIT_STATEMENT,
node.getStart(), "", ", "); //$NON-NLS-1$ //$NON-NLS-2$
return false;
}
// php5.4 ends
private boolean isInsertUseStatement;
public void setInsertUseStatement(boolean isInsertUseStatement) {
// TODO Auto-generated method stub
this.isInsertUseStatement = isInsertUseStatement;
}
}