Lines 48-59
Link Here
|
48 |
import com.sun.source.doctree.DocTree; |
48 |
import com.sun.source.doctree.DocTree; |
49 |
import com.sun.source.tree.ClassTree; |
49 |
import com.sun.source.tree.ClassTree; |
50 |
import com.sun.source.tree.CompilationUnitTree; |
50 |
import com.sun.source.tree.CompilationUnitTree; |
|
|
51 |
import com.sun.source.tree.EnhancedForLoopTree; |
51 |
import com.sun.source.tree.ExpressionStatementTree; |
52 |
import com.sun.source.tree.ExpressionStatementTree; |
52 |
import com.sun.source.tree.ExpressionTree; |
53 |
import com.sun.source.tree.ExpressionTree; |
|
|
54 |
import com.sun.source.tree.ForLoopTree; |
53 |
import com.sun.source.tree.IdentifierTree; |
55 |
import com.sun.source.tree.IdentifierTree; |
54 |
import com.sun.source.tree.MethodInvocationTree; |
56 |
import com.sun.source.tree.MethodInvocationTree; |
55 |
import com.sun.source.tree.Tree; |
57 |
import com.sun.source.tree.Tree; |
56 |
import com.sun.source.tree.Tree.Kind; |
58 |
import com.sun.source.tree.Tree.Kind; |
|
|
59 |
import com.sun.source.tree.TreeVisitor; |
60 |
import com.sun.source.tree.TryTree; |
61 |
import com.sun.source.util.DocTrees; |
57 |
import com.sun.source.util.TreePath; |
62 |
import com.sun.source.util.TreePath; |
58 |
import com.sun.source.util.TreePathScanner; |
63 |
import com.sun.source.util.TreePathScanner; |
59 |
import com.sun.source.util.TreeScanner; |
64 |
import com.sun.source.util.TreeScanner; |
Lines 79-106
Link Here
|
79 |
import javax.lang.model.element.ElementKind; |
84 |
import javax.lang.model.element.ElementKind; |
80 |
import javax.swing.text.BadLocationException; |
85 |
import javax.swing.text.BadLocationException; |
81 |
import javax.tools.JavaFileObject; |
86 |
import javax.tools.JavaFileObject; |
82 |
|
|
|
83 |
import com.sun.source.tree.EnhancedForLoopTree; |
84 |
import com.sun.source.tree.ForLoopTree; |
85 |
import com.sun.source.tree.TreeVisitor; |
86 |
import com.sun.source.tree.TryTree; |
87 |
import com.sun.source.util.DocTrees; |
88 |
import org.netbeans.api.annotations.common.NonNull; |
87 |
import org.netbeans.api.annotations.common.NonNull; |
89 |
import org.netbeans.api.annotations.common.NullAllowed; |
88 |
import org.netbeans.api.annotations.common.NullAllowed; |
90 |
import org.netbeans.api.annotations.common.NullUnknown; |
89 |
import org.netbeans.api.annotations.common.NullUnknown; |
91 |
import org.netbeans.api.java.lexer.JavaTokenId; |
90 |
import org.netbeans.api.java.lexer.JavaTokenId; |
92 |
import org.netbeans.modules.java.source.parsing.JavacParserResult; |
91 |
import org.netbeans.api.java.source.ModificationResult.CreateChange; |
93 |
import org.netbeans.modules.parsing.spi.Parser; |
92 |
import org.netbeans.api.java.source.ModificationResult.Difference; |
94 |
import org.openide.util.Exceptions; |
|
|
95 |
import org.openide.util.Parameters; |
96 |
import static org.netbeans.api.java.source.ModificationResult.*; |
97 |
import org.netbeans.api.lexer.TokenSequence; |
93 |
import org.netbeans.api.lexer.TokenSequence; |
98 |
import org.netbeans.modules.java.source.save.CasualDiff.Diff; |
94 |
import org.netbeans.modules.java.source.builder.CommentHandlerService; |
|
|
95 |
import org.netbeans.modules.java.source.builder.CommentSetImpl; |
99 |
import org.netbeans.modules.java.source.builder.TreeFactory; |
96 |
import org.netbeans.modules.java.source.builder.TreeFactory; |
100 |
import org.netbeans.modules.java.source.parsing.CompilationInfoImpl; |
97 |
import org.netbeans.modules.java.source.parsing.CompilationInfoImpl; |
101 |
import org.netbeans.modules.java.source.parsing.FileObjects; |
98 |
import org.netbeans.modules.java.source.parsing.FileObjects; |
|
|
99 |
import org.netbeans.modules.java.source.parsing.JavacParserResult; |
102 |
import org.netbeans.modules.java.source.pretty.ImportAnalysis2; |
100 |
import org.netbeans.modules.java.source.pretty.ImportAnalysis2; |
|
|
101 |
import org.netbeans.modules.java.source.query.CommentSet.RelativePosition; |
103 |
import org.netbeans.modules.java.source.save.CasualDiff; |
102 |
import org.netbeans.modules.java.source.save.CasualDiff; |
|
|
103 |
import org.netbeans.modules.java.source.save.CasualDiff.Diff; |
104 |
import org.netbeans.modules.java.source.save.DiffContext; |
104 |
import org.netbeans.modules.java.source.save.DiffContext; |
105 |
import org.netbeans.modules.java.source.save.DiffUtilities; |
105 |
import org.netbeans.modules.java.source.save.DiffUtilities; |
106 |
import org.netbeans.modules.java.source.save.ElementOverlay; |
106 |
import org.netbeans.modules.java.source.save.ElementOverlay; |
Lines 109-122
Link Here
|
109 |
import org.netbeans.modules.java.source.transform.ImmutableDocTreeTranslator; |
109 |
import org.netbeans.modules.java.source.transform.ImmutableDocTreeTranslator; |
110 |
import org.netbeans.modules.java.source.transform.ImmutableTreeTranslator; |
110 |
import org.netbeans.modules.java.source.transform.ImmutableTreeTranslator; |
111 |
import org.netbeans.modules.java.source.transform.TreeDuplicator; |
111 |
import org.netbeans.modules.java.source.transform.TreeDuplicator; |
|
|
112 |
import org.netbeans.modules.parsing.spi.Parser; |
112 |
import org.openide.filesystems.FileObject; |
113 |
import org.openide.filesystems.FileObject; |
113 |
import org.openide.filesystems.FileUtil; |
114 |
import org.openide.filesystems.FileUtil; |
114 |
import org.openide.loaders.DataFolder; |
115 |
import org.openide.loaders.DataFolder; |
115 |
import org.openide.loaders.DataObject; |
116 |
import org.openide.loaders.DataObject; |
|
|
117 |
import org.openide.util.Exceptions; |
116 |
import org.openide.util.NbBundle; |
118 |
import org.openide.util.NbBundle; |
117 |
import org.openide.util.Pair; |
119 |
import org.openide.util.Parameters; |
118 |
import org.openide.util.Utilities; |
120 |
import org.openide.util.Utilities; |
119 |
|
121 |
|
|
|
122 |
import static org.netbeans.api.java.source.ModificationResult.*; |
123 |
|
120 |
/**XXX: extends CompilationController now, finish method delegation |
124 |
/**XXX: extends CompilationController now, finish method delegation |
121 |
* |
125 |
* |
122 |
* @author Dusan Balek, Petr Hrebejk, Tomas Zezul |
126 |
* @author Dusan Balek, Petr Hrebejk, Tomas Zezul |
Lines 139-144
Link Here
|
139 |
*/ |
143 |
*/ |
140 |
private Map<Tree, Boolean> introducedTrees; |
144 |
private Map<Tree, Boolean> introducedTrees; |
141 |
|
145 |
|
|
|
146 |
/** |
147 |
* Hint information on rewrites done. Can mark a Tree as `new' which means comments will not be copied for it |
148 |
* and it will not assume other tree's formatting on output. Can link a Tree to one or more other Trees, which |
149 |
* causes the old trees comments to be preserved (copied) should the old trees be removed from the source. |
150 |
*/ |
151 |
private Map<Tree, Tree> rewriteHints = new HashMap<Tree, Tree>(); |
152 |
|
142 |
WorkingCopy(final CompilationInfoImpl impl, ElementOverlay overlay) { |
153 |
WorkingCopy(final CompilationInfoImpl impl, ElementOverlay overlay) { |
143 |
super(impl); |
154 |
super(impl); |
144 |
this.overlay = overlay; |
155 |
this.overlay = overlay; |
Lines 226-231
Link Here
|
226 |
* {@link TreeMaker} for tree element removal. If <code>oldTree</code> is |
237 |
* {@link TreeMaker} for tree element removal. If <code>oldTree</code> is |
227 |
* null, <code>newTree</code> must be of kind |
238 |
* null, <code>newTree</code> must be of kind |
228 |
* {@link Kind#COMPILATION_UNIT COMPILATION_UNIT}. |
239 |
* {@link Kind#COMPILATION_UNIT COMPILATION_UNIT}. |
|
|
240 |
* <p> |
241 |
* Since 0.137, comments in the rewritten node will be automatically assigned to the newTree |
242 |
* node. Use {@link TreeMaker#asRemoved} to discard comments from the oldTree explicitly. |
229 |
* |
243 |
* |
230 |
* |
244 |
* |
231 |
* @param oldTree tree to be replaced, use tree already represented in |
245 |
* @param oldTree tree to be replaced, use tree already represented in |
Lines 239-244
Link Here
|
239 |
* method. |
253 |
* method. |
240 |
* @see GeneratorUtilities#createFromTemplate |
254 |
* @see GeneratorUtilities#createFromTemplate |
241 |
* @see TreeMaker |
255 |
* @see TreeMaker |
|
|
256 |
* @since 0.137 |
242 |
*/ |
257 |
*/ |
243 |
public synchronized void rewrite(@NullAllowed Tree oldTree, @NonNull Tree newTree) { |
258 |
public synchronized void rewrite(@NullAllowed Tree oldTree, @NonNull Tree newTree) { |
244 |
checkConfinement(); |
259 |
checkConfinement(); |
Lines 255-260
Link Here
|
255 |
} |
270 |
} |
256 |
if (oldTree == null || newTree == null) |
271 |
if (oldTree == null || newTree == null) |
257 |
throw new IllegalArgumentException("Null values are not allowed."); |
272 |
throw new IllegalArgumentException("Null values are not allowed."); |
|
|
273 |
Tree t = rewriteHints.get(oldTree); |
274 |
if (t == null) { |
275 |
// if the old tree does not have any association to a new generated node, make an implicit association |
276 |
associateTree(newTree, oldTree, false); |
277 |
} |
258 |
// Perf: trees are collected just when asserts are enabled. |
278 |
// Perf: trees are collected just when asserts are enabled. |
259 |
assert new TreeCollector(introducedTrees, true).scan(newTree, null) != null; |
279 |
assert new TreeCollector(introducedTrees, true).scan(newTree, null) != null; |
260 |
changes.put(oldTree, newTree); |
280 |
changes.put(oldTree, newTree); |
Lines 433-438
Link Here
|
433 |
|
453 |
|
434 |
// Package private methods ------------------------------------------------- |
454 |
// Package private methods ------------------------------------------------- |
435 |
|
455 |
|
|
|
456 |
// static final Collection<Tree> NOT_LINKED = new ArrayList<Tree>(0); |
457 |
static final Tree NOT_LINKED = new Tree() { |
458 |
|
459 |
@Override |
460 |
public Kind getKind() { |
461 |
return Kind.OTHER; |
462 |
} |
463 |
|
464 |
@Override |
465 |
public <R, D> R accept(TreeVisitor<R, D> visitor, D data) { |
466 |
return visitor.visitOther(this, data); |
467 |
} |
468 |
}; |
469 |
|
470 |
/** |
471 |
* Associates a new tree with the original. Only one association is supported, |
472 |
* the last association wins. |
473 |
* |
474 |
* @param nue the new tree |
475 |
* @param original the to-be-replaced original |
476 |
*/ |
477 |
synchronized void associateTree(Tree nue, Tree original, boolean force) { |
478 |
if (rewriteHints == null) { |
479 |
rewriteHints = new HashMap<Tree, Tree>(7); |
480 |
} |
481 |
|
482 |
if (original == null) { |
483 |
Tree ex = rewriteHints.get(nue); |
484 |
if (ex == null || force) { |
485 |
rewriteHints.put(nue, NOT_LINKED); |
486 |
} |
487 |
} else if (original == nue) { |
488 |
return; |
489 |
} else { |
490 |
Tree ex = rewriteHints.get(original); |
491 |
if (ex == null || force) { |
492 |
rewriteHints.put(original, nue); |
493 |
} |
494 |
} |
495 |
} |
496 |
|
436 |
private static String codeForCompilationUnit(CompilationUnitTree topLevel) throws IOException { |
497 |
private static String codeForCompilationUnit(CompilationUnitTree topLevel) throws IOException { |
437 |
return ((JCTree.JCCompilationUnit) topLevel).sourcefile.getCharContent(true).toString(); |
498 |
return ((JCTree.JCCompilationUnit) topLevel).sourcefile.getCharContent(true).toString(); |
438 |
} |
499 |
} |
Lines 500-505
Link Here
|
500 |
Map<Integer, String> userInfo = new HashMap<Integer, String>(); |
561 |
Map<Integer, String> userInfo = new HashMap<Integer, String>(); |
501 |
final Set<Tree> oldTrees = new HashSet<Tree>(); |
562 |
final Set<Tree> oldTrees = new HashSet<Tree>(); |
502 |
|
563 |
|
|
|
564 |
final Map<Tree, Boolean> presentInResult = new IdentityHashMap<Tree, Boolean>(); |
503 |
if (CasualDiff.OLD_TREES_VERBATIM) { |
565 |
if (CasualDiff.OLD_TREES_VERBATIM) { |
504 |
new TreeScanner<Void, Void>() { |
566 |
new TreeScanner<Void, Void>() { |
505 |
private boolean synthetic = false; |
567 |
private boolean synthetic = false; |
Lines 552-557
Link Here
|
552 |
@Override |
614 |
@Override |
553 |
public Void scan(Tree node, Void p) { |
615 |
public Void scan(Tree node, Void p) { |
554 |
addSyntheticTrees(diffContext, node); |
616 |
addSyntheticTrees(diffContext, node); |
|
|
617 |
addPresentInResult(presentInResult, node, true); |
555 |
return super.scan(node, p); |
618 |
return super.scan(node, p); |
556 |
} |
619 |
} |
557 |
}.scan(diffContext.origUnit, null); |
620 |
}.scan(diffContext.origUnit, null); |
Lines 603-620
Link Here
|
603 |
parent2Rewrites.put(currentParent, new IdentityHashMap<Tree, Tree>()); |
666 |
parent2Rewrites.put(currentParent, new IdentityHashMap<Tree, Tree>()); |
604 |
} |
667 |
} |
605 |
} |
668 |
} |
606 |
if(changes.containsKey(tree)) { |
669 |
Tree rev = changes.get(tree); |
|
|
670 |
Tree hint = resolveRewriteHint(tree); |
671 |
if(rev != null) { |
607 |
Map<Tree, Tree> rewrites = parent2Rewrites.get(currentParent); |
672 |
Map<Tree, Tree> rewrites = parent2Rewrites.get(currentParent); |
|
|
673 |
|
674 |
changes.remove(tree); |
608 |
|
675 |
|
609 |
Tree rev = changes.remove(tree); |
676 |
if (hint == null) { |
610 |
|
677 |
addPresentInResult(presentInResult, rev, false); |
|
|
678 |
} |
679 |
//presentInResult.remove(tree); |
611 |
rewrites.put(tree, rev); |
680 |
rewrites.put(tree, rev); |
612 |
|
681 |
|
613 |
scan(rev, p); |
682 |
scan(rev, p); |
614 |
} else { |
683 |
} else { |
|
|
684 |
if (hint == null) { |
685 |
addPresentInResult(presentInResult, rev, false); |
686 |
} |
687 |
addPresentInResult(presentInResult, tree, true); |
615 |
super.scan(tree, p); |
688 |
super.scan(tree, p); |
616 |
} |
689 |
} |
617 |
} else { |
690 |
} else { |
|
|
691 |
addPresentInResult(presentInResult, tree, true); |
618 |
super.scan(tree, p); |
692 |
super.scan(tree, p); |
619 |
} |
693 |
} |
620 |
if (currentParent != null && currentParent.getLeaf() == tree) { |
694 |
if (currentParent != null && currentParent.getLeaf() == tree) { |
Lines 763-768
Link Here
|
763 |
|
837 |
|
764 |
//tagging debug |
838 |
//tagging debug |
765 |
//System.err.println("brandNew=" + brandNew); |
839 |
//System.err.println("brandNew=" + brandNew); |
|
|
840 |
new CommentReplicator(presentInResult.keySet()).scan(diffContext.origUnit, null); |
766 |
|
841 |
|
767 |
for (ClassTree ct : classes) { |
842 |
for (ClassTree ct : classes) { |
768 |
ia.classLeft(); |
843 |
ia.classLeft(); |
Lines 798-803
Link Here
|
798 |
} |
873 |
} |
799 |
} |
874 |
} |
800 |
|
875 |
|
|
|
876 |
private void addPresentInResult(Map<Tree, Boolean> present, Tree t, boolean mark) { |
877 |
present.put(t, Boolean.valueOf(mark)); |
878 |
CommentSetImpl csi = CommentHandlerService.instance(impl.getJavacTask().getContext()).getComments(t); |
879 |
for (RelativePosition pos : RelativePosition.values()) { |
880 |
useComments(csi.getComments(pos)); |
881 |
} |
882 |
} |
883 |
|
884 |
private Set<Comment> usedComments; |
885 |
|
886 |
/* package-private */ List<Comment> useComments(List<Comment> comments) { |
887 |
if (usedComments == null) { |
888 |
usedComments = new HashSet<>(); |
889 |
} |
890 |
usedComments.addAll(comments); |
891 |
return comments; |
892 |
} |
893 |
|
894 |
/** |
895 |
* Copies comments according to rewrite hints:<ul> |
896 |
* <li>copies comments from a tree to an associated tree |
897 |
* <li> |
898 |
*/ |
899 |
private class CommentReplicator extends TreePathScanner<Object, Object> { |
900 |
private final Set<Tree> stillPresent; |
901 |
|
902 |
private boolean collectCommentsFromRemovedNodes; |
903 |
private Map<Tree, Tree> copyTo = new IdentityHashMap<Tree, Tree>(); |
904 |
private final CommentHandlerService commentHandler; |
905 |
private Tree parentToCopy; |
906 |
|
907 |
CommentReplicator(Set<Tree> presentNodes) { |
908 |
this.stillPresent = presentNodes; |
909 |
this.commentHandler = CommentHandlerService.instance(impl.getJavacTask().getContext()); |
910 |
} |
911 |
|
912 |
private Object scanAndReduce(Tree node, Object p, Object r) { |
913 |
return reduce(scan(node, p), r); |
914 |
} |
915 |
|
916 |
private RelativePosition collectToPosition; |
917 |
|
918 |
/** Scan a list of nodes. |
919 |
*/ |
920 |
@Override |
921 |
public Object scan(Iterable<? extends Tree> nodes, Object p) { |
922 |
Object r = null; |
923 |
if (nodes != null) { |
924 |
boolean first = true; |
925 |
Tree saveParent = parentToCopy; |
926 |
RelativePosition savePosition = this.collectToPosition; |
927 |
collectToPosition = RelativePosition.INNER; |
928 |
if (collectCommentsFromRemovedNodes) { |
929 |
// find first such node that it either survived, or has a mapping to the new state. Join all |
930 |
// comments to PRECEDING of such node. |
931 |
for (Tree node : nodes) { |
932 |
Tree target = resolveRewriteHint(node); |
933 |
if (target != null) { |
934 |
if (target != NOT_LINKED) { |
935 |
parentToCopy = target; |
936 |
collectToPosition = RelativePosition.PRECEDING; |
937 |
break; |
938 |
} |
939 |
} else if (stillPresent.contains(node)) { |
940 |
parentToCopy = node; |
941 |
collectToPosition = RelativePosition.PRECEDING; |
942 |
break; |
943 |
} |
944 |
} |
945 |
} |
946 |
boolean reset = false; |
947 |
for (Tree node : nodes) { |
948 |
if (collectCommentsFromRemovedNodes) { |
949 |
Tree target = resolveRewriteHint(node); |
950 |
if (target != null && target != NOT_LINKED) { |
951 |
parentToCopy = target; |
952 |
this.collectToPosition = RelativePosition.INNER; |
953 |
reset = true; |
954 |
} else if (stillPresent.contains(node)) { |
955 |
parentToCopy = node; |
956 |
this.collectToPosition = RelativePosition.INNER; |
957 |
reset = true; |
958 |
} |
959 |
} |
960 |
r = (first ? scan(node, p) : scanAndReduce(node, p, r)); |
961 |
first = false; |
962 |
// reset to trailing, output goes to the anchor node. |
963 |
if (reset) { |
964 |
this.collectToPosition = RelativePosition.TRAILING; |
965 |
} |
966 |
} |
967 |
parentToCopy = saveParent; |
968 |
collectToPosition = savePosition; |
969 |
} |
970 |
return r; |
971 |
} |
972 |
|
973 |
@Override |
974 |
public Object scan(Tree l, Object p) { |
975 |
boolean collectChildren = false; |
976 |
Tree newParentCopy = null; |
977 |
|
978 |
boolean saveCollect = this.collectCommentsFromRemovedNodes; |
979 |
Tree target = resolveRewriteHint(l); |
980 |
if (target == NOT_LINKED) { |
981 |
// do not copy anything from this node and its children |
982 |
collectChildren = false; |
983 |
} else if (target != null) { |
984 |
if (!commentHandler.getComments(target).hasComments()) { |
985 |
if (!stillPresent.contains(l)) { |
986 |
commentHandler.copyComments(l, target, null, usedComments); |
987 |
newParentCopy = target; |
988 |
collectChildren = true; |
989 |
} |
990 |
} |
991 |
} else if (!stillPresent.contains(l)) { // target == null, node removed |
992 |
collectChildren = collectCommentsFromRemovedNodes; |
993 |
if (collectCommentsFromRemovedNodes) { |
994 |
if (parentToCopy != null) { |
995 |
commentHandler.copyComments(l, parentToCopy, collectToPosition, usedComments); |
996 |
} |
997 |
} |
998 |
} |
999 |
if (stillPresent.contains(l)) { |
1000 |
newParentCopy = l; |
1001 |
} |
1002 |
Tree saveParent = parentToCopy; |
1003 |
this.collectCommentsFromRemovedNodes = collectChildren; |
1004 |
if (newParentCopy != null) { |
1005 |
parentToCopy = newParentCopy; |
1006 |
} |
1007 |
Object v = super.scan(l, p); |
1008 |
this.parentToCopy = saveParent; |
1009 |
this.collectCommentsFromRemovedNodes = saveCollect; |
1010 |
return v; |
1011 |
} |
1012 |
|
1013 |
} |
1014 |
|
1015 |
private Tree resolveRewriteHint(Tree orig) { |
1016 |
Tree last; |
1017 |
Tree target = null; |
1018 |
Tree from = orig; |
1019 |
do { |
1020 |
last = target; |
1021 |
target = from; |
1022 |
target = rewriteHints.get(target); |
1023 |
if (target == NOT_LINKED) { |
1024 |
return target; |
1025 |
} |
1026 |
from = target; |
1027 |
} while (target != null); |
1028 |
return last; |
1029 |
} |
1030 |
|
801 |
private List<Difference> processExternalCUs(Map<?, int[]> tag2Span, Set<Tree> syntheticTrees) { |
1031 |
private List<Difference> processExternalCUs(Map<?, int[]> tag2Span, Set<Tree> syntheticTrees) { |
802 |
if (externalChanges == null) { |
1032 |
if (externalChanges == null) { |
803 |
return Collections.<Difference>emptyList(); |
1033 |
return Collections.<Difference>emptyList(); |