Index: dom/org/eclipse/jdt/core/dom/CompilationUnit.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java,v retrieving revision 1.60 diff -u -r1.60 CompilationUnit.java --- dom/org/eclipse/jdt/core/dom/CompilationUnit.java 30 Nov 2004 14:34:38 -0000 1.60 +++ dom/org/eclipse/jdt/core/dom/CompilationUnit.java 5 Jan 2005 16:43:47 -0000 @@ -484,8 +484,12 @@ * @since 3.0 */ public int getExtendedStartPosition(ASTNode node) { - if (this.commentMapper == null) { - return -1; + if (node == null) { + throw new IllegalArgumentException(); + } + if (this.commentMapper == null || node.getAST() != getAST()) { + // fall back: use best info available + return node.getStartPosition(); } else { return this.commentMapper.getExtendedStartPosition(node); } @@ -504,8 +508,12 @@ * @since 3.0 */ public int getExtendedLength(ASTNode node) { - if (this.commentMapper == null) { - return 0; + if (node == null) { + throw new IllegalArgumentException(); + } + if (this.commentMapper == null || node.getAST() != getAST()) { + // fall back: use best info available + return node.getLength(); } else { return this.commentMapper.getExtendedLength(node); } Index: dom/org/eclipse/jdt/core/dom/InternalASTRewrite.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InternalASTRewrite.java,v retrieving revision 1.4 diff -u -r1.4 InternalASTRewrite.java --- dom/org/eclipse/jdt/core/dom/InternalASTRewrite.java 14 Apr 2004 23:03:10 -0000 1.4 +++ dom/org/eclipse/jdt/core/dom/InternalASTRewrite.java 5 Jan 2005 16:43:47 -0000 @@ -20,6 +20,7 @@ import org.eclipse.jdt.core.dom.SimplePropertyDescriptor; import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; +import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer; import org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer; import org.eclipse.jdt.internal.core.dom.rewrite.ListRewriteEvent; import org.eclipse.jdt.internal.core.dom.rewrite.NodeInfoStore; @@ -65,9 +66,23 @@ public TextEdit rewriteAST(IDocument document, Map options) { TextEdit result = new MultiTextEdit(); - CompilationUnit rootNode = getRootNode(); + final CompilationUnit rootNode = getRootNode(); if (rootNode != null) { - ASTRewriteAnalyzer visitor = new ASTRewriteAnalyzer(document, rootNode, result, this.eventStore, this.nodeStore, options); + TargetSourceRangeComputer xsrComputer = new TargetSourceRangeComputer() { + /** + * This implementation of + * {@link TargetSourceRangeComputer#computeSourceRange(ASTNode)} + * is specialized to work in the case of internal AST rewriting, where the + * original AST has been modified from its original form. This means that + * one cannot trust that the root of the given node is the compilation unit. + */ + public SourceRange computeSourceRange(ASTNode node) { + int extendedStartPosition = rootNode.getExtendedStartPosition(node); + int extendedLength = rootNode.getExtendedLength(node); + return new SourceRange(extendedStartPosition, extendedLength); + } + }; + ASTRewriteAnalyzer visitor = new ASTRewriteAnalyzer(document, rootNode, result, this.eventStore, this.nodeStore, options, xsrComputer); rootNode.accept(visitor); } return result; Index: dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java,v retrieving revision 1.14 diff -u -r1.14 ASTRewrite.java --- dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java 3 Dec 2004 17:28:43 -0000 1.14 +++ dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java 5 Jan 2005 16:43:47 -0000 @@ -85,6 +85,13 @@ private final NodeInfoStore nodeStore; /** + * Target source range computer; null means uninitialized; + * lazy initialized to new TargetSourceRangeComputer(). + * @since 3.1 + */ + private TargetSourceRangeComputer targetSourceRangeComputer = null; + + /** * Creates a new instance for describing manipulations of * the given AST. * @@ -140,6 +147,11 @@ * edits to the given document containing the original source * code. The document itself is not modified. *

+ * For nodes in the original that are being replaced or deleted, + * this rewriter computes the adjusted source ranges + * by calling getTargetSourceRangeComputer().computeSourceRange(node). + *

+ *

* Calling this methods does not discard the modifications * on record. Subsequence modifications are added to the ones * already on record. If this method is called again later, @@ -170,7 +182,7 @@ getRewriteEventStore().markMovedNodesRemoved(); CompilationUnit astRoot= (CompilationUnit) rootNode.getRoot(); - ASTRewriteAnalyzer visitor= new ASTRewriteAnalyzer(document, astRoot, result, this.eventStore, this.nodeStore, options); + ASTRewriteAnalyzer visitor= new ASTRewriteAnalyzer(document, astRoot, result, this.eventStore, this.nodeStore, options, getExtendedSourceRangeComputer()); rootNode.accept(visitor); // throws IllegalArgumentException } return result; @@ -499,6 +511,34 @@ public final ASTNode createMoveTarget(ASTNode node) { return createTargetNode(node, true); } + + /** + * Returns the extended source range computer for this AST rewriter. + * The default value is a new ExtendedSourceRangeComputer(). + * + * @return an extended source range computer + * @since 3.1 + */ + public final TargetSourceRangeComputer getExtendedSourceRangeComputer() { + if (this.targetSourceRangeComputer == null) { + // lazy initialize + this.targetSourceRangeComputer = new TargetSourceRangeComputer(); + } + return this.targetSourceRangeComputer; + } + + /** + * Sets the target source range computer for this AST rewriter. + * + * @param computer a target source range computer, + * or null to restore the default value of + * new TargetSourceRangeComputer() + * @since 3.1 + */ + public final void setTargetSourceRangeComputer(TargetSourceRangeComputer computer) { + // if computer==null, rely on lazy init code in getTargetSourceRangeComputer() + this.targetSourceRangeComputer = computer; + } /** * Returns a string suitable for debugging purposes (only). Index: dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java =================================================================== RCS file: /home/eclipse/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java,v retrieving revision 1.14 diff -u -r1.14 ASTRewriteAnalyzer.java --- dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java 30 Nov 2004 22:54:28 -0000 1.14 +++ dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java 5 Jan 2005 16:43:47 -0000 @@ -41,6 +41,7 @@ import org.eclipse.jdt.core.compiler.ITerminalSymbols; import org.eclipse.jdt.core.dom.*; +import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer; import org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteFormatter.BlockContext; import org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteFormatter.NodeMarker; @@ -73,11 +74,12 @@ private final ASTRewriteFormatter formatter; private final NodeInfoStore nodeInfos; private final CompilationUnit astRoot; + private final TargetSourceRangeComputer extendedSourceRangeComputer; /* * Constructor for ASTRewriteAnalyzer. */ - public ASTRewriteAnalyzer(IDocument document, CompilationUnit astRoot, TextEdit rootEdit, RewriteEventStore eventStore, NodeInfoStore nodeInfos, Map options) { + public ASTRewriteAnalyzer(IDocument document, CompilationUnit astRoot, TextEdit rootEdit, RewriteEventStore eventStore, NodeInfoStore nodeInfos, Map options, TargetSourceRangeComputer extendedSourceRangeComputer) { this.astRoot= astRoot; this.eventStore= eventStore; this.document= document; @@ -88,6 +90,8 @@ this.sourceCopyEndNodes= new Stack(); this.formatter= new ASTRewriteFormatter(nodeInfos, eventStore, options, getLineDelimiter()); + + this.extendedSourceRangeComputer = extendedSourceRangeComputer; } final TokenScanner getScanner() { @@ -103,16 +107,28 @@ return this.document; } + /** + * Returns the extended source range computer for this AST rewriter. + * + * @return an extended source range computer (never null) + * @since 3.1 + */ + private TargetSourceRangeComputer getExtendedSourceRangeComputer() { + return this.extendedSourceRangeComputer; + } + final int getExtendedOffset(ASTNode node) { - return this.astRoot.getExtendedStartPosition(node); + return getExtendedSourceRangeComputer().computeSourceRange(node).getStartPosition(); } final int getExtendedLength(ASTNode node) { - return this.astRoot.getExtendedLength(node); + return getExtendedSourceRangeComputer().computeSourceRange(node).getLength(); } final int getExtendedEnd(ASTNode node) { - return this.astRoot.getExtendedStartPosition(node) + this.astRoot.getExtendedLength(node); + TargetSourceRangeComputer.SourceRange range = + getExtendedSourceRangeComputer().computeSourceRange(node); + return range.getStartPosition() + range.getLength(); } final TextEdit getCopySourceEdit(CopySourceInfo info) { Index: dom/org/eclipse/jdt/core/dom/rewrite/TargetSourceRangeComputer.java =================================================================== RCS file: dom/org/eclipse/jdt/core/dom/rewrite/TargetSourceRangeComputer.java diff -N dom/org/eclipse/jdt/core/dom/rewrite/TargetSourceRangeComputer.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dom/org/eclipse/jdt/core/dom/rewrite/TargetSourceRangeComputer.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2005 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom.rewrite; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.CompilationUnit; + +/** + * An object for computing adjusted source ranges for AST nodes + * that are being replaced or deleted. + *

+ * For example, a refactoring like inline method may choose to replace + * calls to the method but leave intact any comments immediately preceding + * the calls. On the other hand, a refactoring like extract method may choose + * to extract not only the nodes for the selected code but also any + * comments preceding or following them. + *

+ *

+ * Clients should subclass if they need to influence the + * the source range to be affected when replacing or deleting a particular node. + * An instance of the subclass should be registered with + * {@link ASTRewrite#setTargetSourceRangeComputer(TargetSourceRangeComputer)}. + * During a call to {@link ASTRewrite#rewriteAST(org.eclipse.jface.text.IDocument, java.util.Map)}, + * the {@link #computeSourceRange(ASTNode)} method on this object will be + * used to compute the source range for a node being deleted or replaced. + *

+ * + * @since 3.1 + */ +public class TargetSourceRangeComputer { + + /** + * Reified source range. Instances are "value" object + * (cannot be modified). + * + * @since 3.1 + */ + public static final class SourceRange { + /** + * 0-based character index, or -1 + * if no source position information is known. + */ + private int startPosition; + + /** + * (possibly 0) length, or 0 + * if no source position information is known. + */ + private int length; + + /** + * Creates a new source range. + * + * @param startPosition the 0-based character index, or -1 + * if no source position information is known + * @param length the (possibly 0) length, or 0 + * if no source position information is known + */ + public SourceRange(int startPosition, int length) { + this.startPosition = startPosition; + this.length = length; + } + + /** + * Returns the start position. + * + * @return the 0-based character index, or -1 + * if no source position information is known + */ + public int getStartPosition() { + return this.startPosition; + } + + /** + * Returns the source length. + * + * @return a (possibly 0) length, or 0 + * if no source position information is known + */ + public int getLength() { + return this.length; + } + } + + /** + * Creates a new target source range computer. + */ + public TargetSourceRangeComputer() { + // do nothing + } + + /** + * Returns the target source range of the given node. Unlike + * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()}, + * the extended source range may include comments and whitespace + * immediately before or after the normal source range for the node. + *

+ * The default implementation uses + * {@link CompilationUnit#getExtendedStartPosition(ASTNode)} + * and {@link CompilationUnit#getExtendedLength(ASTNode)} + * to compute the target source range. Clients may override or + * extend this method to expand or contract the source range of the + * given node. The resulting source range must cover at least the + * original source range of the node. + *

+ * + * @param node the node with a known source range in the compilation unit + * being rewritten + * @return the exact source range in the compilation unit being rewritten + * that should be replaced (or deleted) + */ + public SourceRange computeSourceRange(ASTNode node) { + // TODO (Martin) Is it true that this method will only be called on AST nodes that are part of the original tree and have at least a basic source position? + CompilationUnit cu = (CompilationUnit) node.getRoot(); + return new SourceRange( + cu.getExtendedStartPosition(node), + cu.getExtendedLength(node)); + } +}