diff -r 342dff4f2266 java.hints/src/org/netbeans/modules/java/hints/errors/CreateClassFix.java --- a/java.hints/src/org/netbeans/modules/java/hints/errors/CreateClassFix.java Thu Jun 12 13:19:51 2008 +0200 +++ b/java.hints/src/org/netbeans/modules/java/hints/errors/CreateClassFix.java Wed Jun 25 15:24:23 2008 +0200 @@ -345,7 +345,7 @@ } }); - return Utilities.commitAndComputeChangeInfo(targetFile, diff); + return Utilities.commitAndComputeChangeInfo(targetFile, diff, null); } public String toDebugString(CompilationInfo info) { diff -r 342dff4f2266 java.hints/src/org/netbeans/modules/java/hints/errors/CreateFieldFix.java --- a/java.hints/src/org/netbeans/modules/java/hints/errors/CreateFieldFix.java Thu Jun 12 13:19:51 2008 +0200 +++ b/java.hints/src/org/netbeans/modules/java/hints/errors/CreateFieldFix.java Wed Jun 25 15:24:23 2008 +0200 @@ -131,7 +131,7 @@ } }); - return Utilities.commitAndComputeChangeInfo(targetFile, diff); + return Utilities.commitAndComputeChangeInfo(targetFile, diff, null); } String toDebugString(CompilationInfo info) { diff -r 342dff4f2266 java.hints/src/org/netbeans/modules/java/hints/errors/CreateMethodFix.java --- a/java.hints/src/org/netbeans/modules/java/hints/errors/CreateMethodFix.java Thu Jun 12 13:19:51 2008 +0200 +++ b/java.hints/src/org/netbeans/modules/java/hints/errors/CreateMethodFix.java Wed Jun 25 15:24:23 2008 +0200 @@ -83,11 +83,13 @@ private String name; private String inFQN; private String methodDisplayName; + private CompilationInfo info; public CreateMethodFix(CompilationInfo info, String name, Set modifiers, TypeElement target, TypeMirror returnType, List argumentTypes, List argumentNames, FileObject targetFile) { this.name = name; this.inFQN = target.getQualifiedName().toString(); this.cpInfo = info.getClasspathInfo(); + this.info = info; this.modifiers = modifiers; this.targetFile = targetFile; this.target = ElementHandle.create(target); @@ -140,6 +142,8 @@ public ChangeInfo implement() throws IOException { //use the original cp-info so it is "sure" that the proposedType can be resolved: JavaSource js = JavaSource.create(cpInfo, targetFile); + //XXX tag used for selection + final String methodBodyTag = "mbody"; //NOI18N ModificationResult diff = js.runModificationTask(new Task() { public void run(final WorkingCopy working) throws IOException { @@ -180,6 +184,11 @@ } BlockTree body = targetType.getKind().isClass() ? createDefaultMethodBody(working, returnType) : null; + + if(body != null && !body.getStatements().isEmpty()) { + working.tag(body.getStatements().get(0), methodBodyTag); + } + MethodTree mt = make.Method(make.Modifiers(modifiers), name, returnType != null ? make.Type(returnType) : null, Collections.emptyList(), argTypes, Collections.emptyList(), body, null); ClassTree decl = GeneratorUtils.insertClassMember(working, targetTree, mt); @@ -187,7 +196,7 @@ } }); - return Utilities.commitAndComputeChangeInfo(targetFile, diff); + return Utilities.commitAndComputeChangeInfo(targetFile, diff, methodBodyTag); } private void addArguments(CompilationInfo info, StringBuilder value) { @@ -244,6 +253,6 @@ } return make.Block(blockStatements, false); } - + } diff -r 342dff4f2266 java.hints/src/org/netbeans/modules/java/hints/errors/Utilities.java --- a/java.hints/src/org/netbeans/modules/java/hints/errors/Utilities.java Thu Jun 12 13:19:51 2008 +0200 +++ b/java.hints/src/org/netbeans/modules/java/hints/errors/Utilities.java Wed Jun 25 15:24:23 2008 +0200 @@ -48,6 +48,7 @@ import com.sun.source.tree.NewClassTree; import com.sun.source.tree.ParameterizedTypeTree; import com.sun.source.tree.Scope; +import com.sun.source.tree.StatementTree; import com.sun.source.tree.Tree; import com.sun.source.util.TreePath; import java.io.IOException; @@ -213,10 +214,21 @@ } } - - public static ChangeInfo commitAndComputeChangeInfo(FileObject target, ModificationResult diff) throws IOException { + + /** + * Commits changes and provides selection bounds + * + * @param target target FileObject + * @param diff set of changes made by ModificationTask + * @param tag mark used for selection of generated text + * @return set of changes made by hint + * @throws java.io.IOException + */ + public static ChangeInfo commitAndComputeChangeInfo(FileObject target, final ModificationResult diff, final Object tag) throws IOException { List differences = diff.getDifferences(target); ChangeInfo result = null; + + diff.commit(); try { if (differences != null) { @@ -229,14 +241,19 @@ doc = start.getCloneableEditorSupport().openDocument(); } - final Position[] pos = new Position[1]; + final Position[] pos = new Position[2]; final Document fdoc = doc; doc.render(new Runnable() { - public void run() { try { - pos[0] = NbDocument.createPosition(fdoc, start.getOffset(), Position.Bias.Backward); + if(diff.getSpan(tag) != null) { + pos[0] = fdoc.createPosition(diff.getSpan(tag)[0]); + pos[1] = fdoc.createPosition(diff.getSpan(tag)[1]); + } else { + pos[0] = NbDocument.createPosition(fdoc, start.getOffset(), Position.Bias.Backward); + pos[1] = pos[0]; + } } catch (BadLocationException ex) { Exceptions.printStackTrace(ex); } @@ -244,7 +261,7 @@ }); if (pos[0] != null) { - result = new ChangeInfo(target, pos[0], pos[0]); + result = new ChangeInfo(target, pos[0], pos[1]); } break; @@ -254,8 +271,6 @@ } catch (IOException e) { Exceptions.printStackTrace(e); } - - diff.commit(); return result; } diff -r 342dff4f2266 java.source/apichanges.xml --- a/java.source/apichanges.xml Thu Jun 12 13:19:51 2008 +0200 +++ b/java.source/apichanges.xml Wed Jun 25 15:24:23 2008 +0200 @@ -105,6 +105,17 @@ + + + Added ModificationResult.getSpan and WorkingCopy.tag + + + + + + Added Methods allowing tagging of trees and getting their span inside modified document. + + Added TypeUtilities.substitute diff -r 342dff4f2266 java.source/nbproject/project.properties --- a/java.source/nbproject/project.properties Thu Jun 12 13:19:51 2008 +0200 +++ b/java.source/nbproject/project.properties Wed Jun 25 15:24:23 2008 +0200 @@ -43,7 +43,7 @@ javadoc.title=Java Source javadoc.arch=${basedir}/arch.xml javadoc.apichanges=${basedir}/apichanges.xml -spec.version.base=0.36.0 +spec.version.base=0.37.0 test.qa-functional.cp.extra=${refactoring.java.dir}/modules/ext/javac-api-nb-7.0-b07.jar test.unit.run.cp.extra=${o.n.core.dir}/core/core.jar:\ ${o.n.core.dir}/lib/boot.jar:\ diff -r 342dff4f2266 java.source/src/org/netbeans/api/java/source/JavaSource.java --- a/java.source/src/org/netbeans/api/java/source/JavaSource.java Thu Jun 12 13:19:51 2008 +0200 +++ b/java.source/src/org/netbeans/api/java/source/JavaSource.java Wed Jun 25 15:24:23 2008 +0200 @@ -857,7 +857,7 @@ * @see Task for information about implementation requirements * @param task The task which. */ - public ModificationResult runModificationTask(Task task) throws IOException { + public ModificationResult runModificationTask(Task task) throws IOException { if (task == null) { throw new IllegalArgumentException ("Task cannot be null"); //NOI18N } @@ -914,7 +914,7 @@ assert currentInfo != null; WorkingCopy copy = new WorkingCopy (currentInfo); task.run (copy); - List diffs = copy.getChanges(); + List diffs = copy.getChanges(result.tag2Span); if (diffs != null && diffs.size() > 0) result.diffs.put(currentInfo.getFileObject(), diffs); } @@ -965,7 +965,7 @@ if (!ci.needsRestart) { jt = ci.getJavacTask(); Log.instance(jt.getContext()).nerrors = 0; - List diffs = copy.getChanges(); + List diffs = copy.getChanges(result.tag2Span); if (diffs != null && diffs.size() > 0) result.diffs.put(ci.getFileObject(), diffs); activeFile = null; diff -r 342dff4f2266 java.source/src/org/netbeans/api/java/source/ModificationResult.java --- a/java.source/src/org/netbeans/api/java/source/ModificationResult.java Thu Jun 12 13:19:51 2008 +0200 +++ b/java.source/src/org/netbeans/api/java/source/ModificationResult.java Wed Jun 25 15:24:23 2008 +0200 @@ -71,6 +71,7 @@ private JavaSource js; Map> diffs = new HashMap>(); + Map tag2Span = new IdentityHashMap(); /** Creates a new instance of ModificationResult */ ModificationResult(final JavaSource js) { @@ -332,6 +333,16 @@ return writer.toString(); } + + /** + * Provides span of tree tagged with {@code tag} + * @param tag + * @return borders in target document + * @since 0.37 + */ + public int[] getSpan(Object tag) { + return tag2Span.get(tag); + } public static class Difference { Kind kind; diff -r 342dff4f2266 java.source/src/org/netbeans/api/java/source/WorkingCopy.java --- a/java.source/src/org/netbeans/api/java/source/WorkingCopy.java Thu Jun 12 13:19:51 2008 +0200 +++ b/java.source/src/org/netbeans/api/java/source/WorkingCopy.java Wed Jun 25 15:24:23 2008 +0200 @@ -57,6 +57,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -94,6 +95,7 @@ private Map userInfo; private boolean afterCommit = false; private TreeMaker treeMaker; + private Map tree2Tag; WorkingCopy(final CompilationInfoImpl impl) { super(impl); @@ -105,6 +107,7 @@ treeMaker = new TreeMaker(this, TreeFactory.instance(getContext())); changes = new IdentityHashMap(); + tree2Tag = new IdentityHashMap(); externalChanges = null; textualChanges = new HashSet(); userInfo = new HashMap(); @@ -230,6 +233,16 @@ userInfo.put(start, NbBundle.getMessage(CasualDiff.class,"TXT_RenameInComment")); //NOI18N } + /** + * Tags a tree. Used in {@code ModificationResult} to determine position of tree inside document. + * @param t the tree to be tagged + * @param tag an {@code Object} used as tag + * @since 0.37 + */ + public synchronized void tag(Tree t, Object tag) { + tree2Tag.put(t, tag); + } + // Package private methods ------------------------------------------------- private static void commit(CompilationUnitTree topLevel, List diffs, SourceRewriter out) throws IOException, BadLocationException { @@ -284,8 +297,8 @@ private static boolean REWRITE_WHOLE_FILE = Boolean.getBoolean(WorkingCopy.class.getName() + ".rewrite-whole-file"); - private List processCurrentCompilationUnit() throws IOException, BadLocationException { - final Set pathsToRewrite = new HashSet(); + private List processCurrentCompilationUnit(Map tag2Span) throws IOException, BadLocationException { + final Set pathsToRewrite = new LinkedHashSet(); final Map> parent2Rewrites = new IdentityHashMap>(); boolean fillImports = true; @@ -376,9 +389,12 @@ ia.classEntered(ct); } - translator.attach(getContext(), ia, getCompilationUnit()); + translator.attach(getContext(), ia, getCompilationUnit(), tree2Tag); Tree brandNew = translator.translate(path.getLeaf(), parent2Rewrites.get(path)); + + //tagging debug + //System.err.println("brandNew=" + brandNew); for (ClassTree ct : classes) { ia.classLeft(); @@ -388,14 +404,14 @@ fillImports = false; } - diffs.addAll(CasualDiff.diff(getContext(), this, path, (JCTree) brandNew, userInfo)); + diffs.addAll(CasualDiff.diff(getContext(), this, path, (JCTree) brandNew, userInfo, tree2Tag, tag2Span)); } if (fillImports) { List nueImports = ia.getImports(); if (nueImports != null) { //may happen if no changes, etc. - diffs.addAll(CasualDiff.diff(getContext(), this, getCompilationUnit().getImports(), nueImports, userInfo)); + diffs.addAll(CasualDiff.diff(getContext(), this, getCompilationUnit().getImports(), nueImports, userInfo, tree2Tag, tag2Span)); } } @@ -425,7 +441,7 @@ for (CompilationUnitTree t : externalChanges.values()) { Translator translator = new Translator(); - translator.attach(getContext(), new ImportAnalysis2(getContext()), t); + translator.attach(getContext(), new ImportAnalysis2(getContext()), t, tree2Tag); CompilationUnitTree nue = (CompilationUnitTree) translator.translate(t, changes); @@ -437,7 +453,7 @@ return result; } - List getChanges() throws IOException, BadLocationException { + List getChanges(Map tag2Span) throws IOException, BadLocationException { if (afterCommit) throw new IllegalStateException("The commit method can be called only once on a WorkingCopy instance"); //NOI18N afterCommit = true; @@ -449,7 +465,7 @@ List result = new LinkedList(); - result.addAll(processCurrentCompilationUnit()); + result.addAll(processCurrentCompilationUnit(tag2Span)); result.addAll(processExternalCUs()); return result; diff -r 342dff4f2266 java.source/src/org/netbeans/modules/java/source/pretty/VeryPretty.java --- a/java.source/src/org/netbeans/modules/java/source/pretty/VeryPretty.java Thu Jun 12 13:19:51 2008 +0200 +++ b/java.source/src/org/netbeans/modules/java/source/pretty/VeryPretty.java Wed Jun 25 15:24:23 2008 +0200 @@ -66,6 +66,7 @@ import java.util.ArrayList; import java.util.LinkedList; +import java.util.Map; import org.netbeans.api.java.lexer.JavaTokenId; import org.netbeans.api.java.source.Comment.Style; import org.netbeans.api.java.source.CompilationInfo; @@ -105,21 +106,34 @@ private int toOffset = -1; private boolean containsError = false; + private final Map tree2Tag; + private final Map tag2Span; + private int initialOffset = 0; + public VeryPretty(CompilationInfo cInfo) { - this(cInfo, CodeStyle.getDefault(null)); + this(cInfo, CodeStyle.getDefault(null), null, null); } public VeryPretty(CompilationInfo cInfo, CodeStyle cs) { - this(JavaSourceAccessor.getINSTANCE().getJavacTask(cInfo).getContext(), cs); + this(cInfo, cs, null, null); + } + + public VeryPretty(CompilationInfo cInfo, CodeStyle cs, Map tree2Tag, Map tag2Span) { + this(JavaSourceAccessor.getINSTANCE().getJavacTask(cInfo).getContext(), cs, tree2Tag, tag2Span); this.cInfo = cInfo; this.origUnit = (JCCompilationUnit) cInfo.getCompilationUnit(); } - public VeryPretty(Context context) { - this(context, CodeStyle.getDefault(null)); + public VeryPretty(CompilationInfo cInfo, CodeStyle cs, Map tree2Tag, Map tag2Span, int initialOffset) { + this(cInfo, cs, tree2Tag, tag2Span); + this.initialOffset = initialOffset; //provide intial offset of this priter } - public VeryPretty(Context context, CodeStyle cs) { + public VeryPretty(Context context) { + this(context, CodeStyle.getDefault(null), null, null); + } + + public VeryPretty(Context context, CodeStyle cs, Map tree2Tag, Map tag2Span) { names = Name.Table.instance(context); enclClassName = names.empty; commentHandler = CommentHandlerService.instance(context); @@ -132,6 +146,16 @@ this.cs = cs; out = new CharBuffer(cs.getRightMargin(), cs.getTabSize(), cs.expandTabToSpaces()); this.indentSize = cs.getIndentSize(); + this.tree2Tag = tree2Tag; + this.tag2Span = (Map) tag2Span;//XXX + } + + public void setInitialOffset(int offset) { + initialOffset = offset < 0 ? 0 : offset; + } + + public int getInitialOffset() { + return initialOffset; } @Override @@ -189,9 +213,25 @@ blankLines(t, true); toLeftMargin(); printPrecedingComments(t, true); - t.accept(this); + doAccept(t); printTrailingComments(t, true); blankLines(t, false); + } + + private void doAccept(JCTree t) { + int start = toString().length(); + + t.accept(this); + + int end = toString().length(); + + System.err.println("t: " + t); + System.err.println("thr=" + System.identityHashCode(t)); + Object tag = tree2Tag != null ? tree2Tag.get(t) : null; + + if (tag != null) { + tag2Span.put(tag, new int[]{start + initialOffset, end + initialOffset}); + } } public String reformat(JCTree t, int fromOffset, int toOffset, int indent) { @@ -1499,7 +1539,7 @@ } else { int prevPrec = this.prec; this.prec = prec; - tree.accept(this); + doAccept(tree); this.prec = prevPrec; } } @@ -1871,7 +1911,7 @@ private void printComment(Comment comment, boolean preceding, boolean printWhitespace) { if (Comment.Style.WHITESPACE == comment.style()) { - if (printWhitespace) { + if (false && printWhitespace) { char[] data = comment.getText().toCharArray(); int n = -1; for (int i = 0; i < data.length; i++) { diff -r 342dff4f2266 java.source/src/org/netbeans/modules/java/source/save/CasualDiff.java --- a/java.source/src/org/netbeans/modules/java/source/save/CasualDiff.java Thu Jun 12 13:19:51 2008 +0200 +++ b/java.source/src/org/netbeans/modules/java/source/save/CasualDiff.java Wed Jun 25 15:24:23 2008 +0200 @@ -47,7 +47,6 @@ import org.netbeans.api.java.source.Comment.Style; import org.netbeans.modules.java.source.transform.FieldGroupTree; import static com.sun.source.tree.Tree.*; -import org.netbeans.api.java.lexer.JavaTokenId; import org.netbeans.api.lexer.TokenSequence; import org.netbeans.modules.java.source.builder.CommentHandlerService; import org.netbeans.api.java.source.Comment; @@ -85,19 +84,23 @@ private static final Logger LOG = Logger.getLogger(CasualDiff.class.getName()); private Map diffInfo = new HashMap(); + private final Map tree2Tag; + private final Map tag2Span; // used for diffing var def, when parameter is printed, annotation of // such variable should not provide new line at the end. private boolean parameterPrint = false; - protected CasualDiff(Context context, WorkingCopy workingCopy) { + protected CasualDiff(Context context, WorkingCopy workingCopy, Map tree2Tag, Map tag2Span) { diffs = new ListBuffer(); comments = CommentHandlerService.instance(context); this.workingCopy = workingCopy; this.tokenSequence = workingCopy.getTokenHierarchy().tokenSequence(JavaTokenId.language()); this.origText = workingCopy.getText(); this.context = context; - printer = new VeryPretty(workingCopy, CodeStyle.getDefault(null)); + this.tree2Tag = tree2Tag; + this.tag2Span = (Map) tag2Span;//XXX + printer = new VeryPretty(workingCopy, CodeStyle.getDefault(null), tree2Tag, tag2Span); } public com.sun.tools.javac.util.List getDiffs() { @@ -108,9 +111,11 @@ WorkingCopy copy, TreePath oldTreePath, JCTree newTree, - Map userInfo) + Map userInfo, + Map tree2Tag, + Map tag2Span) { - CasualDiff td = new CasualDiff(context, copy); + CasualDiff td = new CasualDiff(context, copy, tree2Tag, tag2Span); JCTree oldTree = (JCTree) oldTreePath.getLeaf(); td.oldTopLevel = (JCCompilationUnit) (oldTree.getKind() == Kind.COMPILATION_UNIT ? oldTree : copy.getCompilationUnit()); @@ -125,6 +130,7 @@ } int[] bounds = td.getBounds(oldTree); + td.printer.setInitialOffset(bounds[0]); boolean isCUT = oldTree.getKind() == Kind.COMPILATION_UNIT; int start = isCUT ? 0 : bounds[0]; int end = isCUT ? td.workingCopy.getText().length() : bounds[1]; @@ -175,9 +181,11 @@ WorkingCopy copy, List original, List nue, - Map userInfo) + Map userInfo, + Map tree2Tag, + Map tag2Span) { - CasualDiff td = new CasualDiff(context, copy); + CasualDiff td = new CasualDiff(context, copy, tree2Tag, tag2Span); td.oldTopLevel = (JCCompilationUnit) copy.getCompilationUnit(); int start = td.oldTopLevel.getPackageName() != null ? td.endPos(td.oldTopLevel.getPackageName()) : 0; @@ -2250,7 +2258,7 @@ found = true; VeryPretty oldPrinter = this.printer; int old = oldPrinter.indent(); - this.printer = new VeryPretty(workingCopy); + this.printer = new VeryPretty(workingCopy, CodeStyle.getDefault(null), tree2Tag, tag2Span, oldPrinter.toString().length() + oldPrinter.getInitialOffset());//XXX this.printer.reset(old); int index = oldList.indexOf(oldT); int[] poss = estimator.getPositions(index); @@ -2266,7 +2274,7 @@ if (lastdel != null && treesMatch(item.element, lastdel, false)) { VeryPretty oldPrinter = this.printer; int old = oldPrinter.indent(); - this.printer = new VeryPretty(workingCopy); + this.printer = new VeryPretty(workingCopy, CodeStyle.getDefault(null), tree2Tag, tag2Span, oldPrinter.toString().length() + oldPrinter.getInitialOffset());//XXX this.printer.reset(old); int index = oldList.indexOf(lastdel); int[] poss = estimator.getPositions(index); @@ -2465,7 +2473,7 @@ * just returns. * * @param oldT original tree in source code - * @param newT tree to repace the original tree + * @param newT tree to replace the original tree * @return position in original source */ protected int diffTree(JCTree oldT, JCTree newT, int[] elementBounds) { @@ -2473,6 +2481,20 @@ } protected int diffTree(JCTree oldT, JCTree newT, JCTree parent /*used only for modifiers*/, int[] elementBounds) { + Object t = tree2Tag.get(newT); + int result; + if (t != null) { + int start = printer.toString().length(); + result = diffTreeImpl(oldT, newT, parent, elementBounds); + int end = printer.toString().length(); + tag2Span.put(t, new int[]{start + printer.getInitialOffset(), end + printer.getInitialOffset()}); + } else { + result = diffTreeImpl(oldT, newT, parent, elementBounds); + } + return result; + } + + protected int diffTreeImpl(JCTree oldT, JCTree newT, JCTree parent /*used only for modifiers*/, int[] elementBounds) { if (oldT == null && newT != null) throw new IllegalArgumentException("Null is not allowed in parameters."); diff -r 342dff4f2266 java.source/src/org/netbeans/modules/java/source/transform/ImmutableTreeTranslator.java --- a/java.source/src/org/netbeans/modules/java/source/transform/ImmutableTreeTranslator.java Thu Jun 12 13:19:51 2008 +0200 +++ b/java.source/src/org/netbeans/modules/java/source/transform/ImmutableTreeTranslator.java Wed Jun 25 15:24:23 2008 +0200 @@ -51,6 +51,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.netbeans.modules.java.source.builder.ASTService; import org.netbeans.modules.java.source.builder.CommentHandlerService; import org.netbeans.modules.java.source.builder.QualIdentTree; @@ -86,17 +87,19 @@ protected ASTService model; private CompilationUnitTree topLevel; private ImportAnalysis2 importAnalysis; + private Map tree2Tag; - public void attach(Context context, ImportAnalysis2 importAnalysis, CompilationUnitTree topLevel) { + public void attach(Context context, ImportAnalysis2 importAnalysis, CompilationUnitTree topLevel, Map tree2Tag) { make = TreeFactory.instance(context); comments = CommentHandlerService.instance(context); model = ASTService.instance(context); this.importAnalysis = importAnalysis; this.topLevel = topLevel; + this.tree2Tag = tree2Tag; } public void attach(Context context) { - attach(context, new ImportAnalysis2(context), null); + attach(context, new ImportAnalysis2(context), null, null); } public void release() { @@ -112,8 +115,15 @@ public Tree translate(Tree tree) { if (tree == null) return null; - else - return tree.accept(this, null); + else { + Tree t = tree.accept(this, null); + + if (tree2Tag != null && tree != t) { + tree2Tag.put(t, tree2Tag.get(tree)); + } + + return t; + } } public T translateClassRef(T tree) {