1 19 20 package org.netbeans.modules.java.source.builder; 21 22 import org.netbeans.modules.java.source.builder.ASTService; 23 import org.netbeans.api.java.source.Comment; 24 import org.netbeans.api.java.source.query.CommentHandler; 25 import org.netbeans.api.java.source.query.CommentSet; 26 import org.netbeans.modules.java.source.engine.ASTModel; 27 28 import com.sun.source.tree.CompilationUnitTree; 29 import com.sun.source.tree.Tree; 30 import com.sun.tools.javac.tree.JCTree; 31 32 import com.sun.tools.javac.tree.JCTree.*; 33 import com.sun.tools.javac.tree.TreeScanner; 34 import com.sun.tools.javac.util.Context; 35 36 import java.util.*; 37 38 import static org.netbeans.modules.java.source.builder.BufferRun.Kind.*; 39 import static org.netbeans.api.java.source.Comment.Style.*; 40 import static com.sun.tools.javac.parser.Token.*; 41 42 45 public class CommentHandlerService implements CommentHandler { 46 private static final Context.Key<CommentHandlerService> commentHandlerKey = 47 new Context.Key<CommentHandlerService>(); 48 49 50 public static CommentHandlerService instance(Context context) { 51 CommentHandlerService instance = context.get(commentHandlerKey); 52 if (instance == null) { 53 instance = new CommentHandlerService(context); 54 setCommentHandler(context, instance); 55 } 56 return instance; 57 } 58 59 62 public static void setCommentHandler(Context context, CommentHandlerService instance) { 63 assert context.get(commentHandlerKey) == null; 64 context.put(commentHandlerKey, instance); 65 } 66 67 private Map<Tree, CommentSetImpl> map = new WeakHashMap<Tree, CommentSetImpl>(); 68 protected ASTModel model; 69 70 private CommentHandlerService(Context context) { 71 model = ASTService.instance(context); 72 } 73 74 public boolean hasComments(Tree tree) { 75 synchronized (map) { 76 return map.containsKey(tree); 77 } 78 } 79 80 public CommentSet getComments(Tree tree) { 81 synchronized (map) { 82 CommentSetImpl cs = map.get(tree); 83 if (cs == null) { 84 cs = new CommentSetImpl(); 85 map.put(tree, cs); 86 } 87 return cs; 88 } 89 } 90 91 95 public void copyComments(Tree fromTree, Tree toTree) { 96 synchronized (map) { 97 CommentSetImpl from = map.get(fromTree); 98 if (from != null) { 99 CommentSetImpl to = map.get(toTree); 100 if (to == null) { 101 to = (CommentSetImpl)from.clone(); 102 to.setTree(toTree); 103 map.put(toTree, to); 104 } 105 else { 106 to.addPrecedingComments(from.getPrecedingComments()); 107 to.addTrailingComments(from.getTrailingComments()); 108 } 109 } 110 } 111 } 112 113 117 public void addComment(Tree tree, Comment c) { 118 synchronized (map) { 119 CommentSetImpl set = map.get(tree); 120 if (set == null) { 121 set = new CommentSetImpl(); 122 map.put(tree, set); 123 } 124 set.addPrecedingComment(c); 125 } 126 } 127 128 131 public void mapComments(final CompilationUnitTree compilationUnit, CharSequence sbuf, BufferRunQueue runs) { 132 final JCCompilationUnit toplevel = (JCCompilationUnit)compilationUnit; 133 final SortedMap<Integer , JCTree> positions = getPositions(toplevel); 134 if (positions.size() == 0) 135 return; 136 JCTree lastTree = null; 137 LineColMapper lineCol = new LineColMapper() { 138 public int getColumn(int offset) { 139 return toplevel.lineMap.getColumnNumber(offset); 140 } 141 public int getLine(int offset) { 142 return toplevel.lineMap.getLineNumber(offset); 143 } 144 }; 145 146 CommentSetImpl topComments = (CommentSetImpl)getComments(toplevel); 148 for (Iterator<BufferRun> iter = runs.iterator(); iter.hasNext();) { 149 BufferRun run = iter.next(); 150 if (run.getKind() == TOKEN) 151 break; 152 else if (run.getKind() == COMMENT) { 153 CommentRun cr = (CommentRun)run; 154 if (cr.getStyle() == JAVADOC) 155 break; Comment c = cr.toComment(cr.getString(sbuf), lineCol.getColumn(cr.getStart())); 157 topComments.addPrecedingComment(c); 158 } 159 } 160 161 for (int pos : positions.keySet()) { 162 JCTree tree = positions.get(pos); 163 int start = runs.findRunStartingAt(model.getStartPos(tree)); 164 if (start == (-1)) continue; 166 mapComments(start, tree, lastTree, sbuf, runs, lineCol); 167 int endPos = model.getEndPos(tree, toplevel); 168 int tail = runs.findRunEndingWith(endPos); 169 if (tail == (-1)) 170 continue; 171 BufferRun br = runs.get(tail); 172 if (br.getKind() == TOKEN && ((TokenRun)br).getToken() == RBRACE) 173 mapTrailingBlockComments(start, tail, tree, getComments(tree), sbuf, runs, lineCol); 174 lastTree = tree; 175 } 176 177 int tail = runs.findRunEndingWith(model.getEndPos(toplevel, toplevel)) + 1; 179 while (tail < runs.size()) { 180 if (runs.get(tail).getKind() == COMMENT) { 181 CommentRun cr = (CommentRun)runs.get(tail); 182 Comment c = cr.toComment(cr.getString(sbuf), lineCol.getColumn(cr.getStart())); 183 topComments.addTrailingComment(c); 184 } 185 tail++; 186 } 187 } 188 189 private void mapTrailingBlockComments(int begin, int end, JCTree tree, CommentSet comments, CharSequence sbuf, 190 BufferRunQueue runs, LineColMapper lineCol) { 191 while (--end > begin && runs.get(end).getKind() != TOKEN) { 192 BufferRun br = runs.get(end); 193 if (br.getKind() == COMMENT) { 194 CommentRun cr = (CommentRun)br; 195 Comment c = cr.toComment(cr.getString(sbuf), lineCol.getColumn(cr.getStart())); 196 comments.addTrailingComment(c); 197 } 198 } 199 } 200 201 private interface LineColMapper { 202 int getColumn(int offset); 203 int getLine(int offset); 204 } 205 206 private void mapComments(int startRun, JCTree tree, JCTree lastTree, CharSequence sbuf, BufferRunQueue runs, LineColMapper lineCol) { 207 assert startRun != -1; 208 int i = startRun - 1; 209 int lastEOL = -1; 210 while (i >= 0 && runs.get(i).getKind() != TOKEN) { 211 if (runs.get(i).getKind() == LINE_ENDING) 212 lastEOL = lineCol.getLine(runs.get(i).getStart()); 213 i--; 214 } 215 216 while (++i < startRun) { 217 if (runs.get(i).getKind() == COMMENT) { 218 CommentRun cr = (CommentRun)runs.get(i); 219 Comment c = cr.toComment(cr.getString(sbuf), lineCol.getColumn(cr.getStart())); 220 if (lastTree != null && lineCol.getLine(cr.getEnd()) == lastEOL) { 221 CommentSetImpl cs = (CommentSetImpl)getComments(lastTree); 223 cs.addTrailingComment(c); 224 } else 225 addComment(tree, c); 226 } 227 } 228 } 229 230 234 private CommentSetImpl flushTrailingComments(CommentSetImpl comments, CommentSetImpl lastComments) { 235 List<Comment> cmts = comments.getPrecedingComments(); 236 if (cmts.isEmpty()) 237 return comments; 238 for (Comment c : cmts) 239 lastComments.addTrailingComment(c); 240 return new CommentSetImpl(); } 242 243 252 private SortedMap<Integer , JCTree> getPositions(JCCompilationUnit tree) { 253 final SortedMap<Integer , JCTree> positions = new TreeMap<Integer , JCTree>(); 254 tree.accept(new TreeScanner() { 255 @Override 256 public void scan(JCTree tree) { 257 if (tree != null) { 258 tree.accept(this); 260 int pos = model.getStartPos(tree); 261 if (pos != com.sun.tools.javac.util.Position.NOPOS) 262 positions.put(pos, tree); 263 } 264 } 265 @Override 266 public void visitTypeIdent(JCPrimitiveTypeTree tree) { 267 super.visitTypeIdent(tree); 268 } 269 @Override 270 public void visitMethodDef(JCMethodDecl tree) { 271 super.visitMethodDef(tree); 272 } 273 }); 274 return positions; 275 } 276 } 277 | Popular Tags |