DocTreeMaker.java revision 3337:cba09a2e6ae9
1/* 2 * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.tools.javac.tree; 27 28import java.text.BreakIterator; 29import java.util.ArrayList; 30import java.util.Collection; 31import java.util.EnumSet; 32import java.util.List; 33import java.util.ListIterator; 34 35import javax.lang.model.element.Name; 36import javax.tools.Diagnostic; 37import javax.tools.JavaFileObject; 38 39import com.sun.source.doctree.AttributeTree.ValueKind; 40import com.sun.source.doctree.DocTree; 41import com.sun.source.doctree.DocTree.Kind; 42import com.sun.source.doctree.EndElementTree; 43import com.sun.source.doctree.IdentifierTree; 44import com.sun.source.doctree.ReferenceTree; 45import com.sun.source.doctree.StartElementTree; 46import com.sun.source.doctree.TextTree; 47import com.sun.source.util.DocTreeFactory; 48import com.sun.tools.doclint.HtmlTag; 49import com.sun.tools.javac.api.JavacTrees; 50import com.sun.tools.javac.parser.ParserFactory; 51import com.sun.tools.javac.parser.ReferenceParser; 52import com.sun.tools.javac.parser.Tokens.Comment; 53import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; 54import com.sun.tools.javac.tree.DCTree.DCAttribute; 55import com.sun.tools.javac.tree.DCTree.DCAuthor; 56import com.sun.tools.javac.tree.DCTree.DCComment; 57import com.sun.tools.javac.tree.DCTree.DCDeprecated; 58import com.sun.tools.javac.tree.DCTree.DCDocComment; 59import com.sun.tools.javac.tree.DCTree.DCDocRoot; 60import com.sun.tools.javac.tree.DCTree.DCEndElement; 61import com.sun.tools.javac.tree.DCTree.DCEntity; 62import com.sun.tools.javac.tree.DCTree.DCErroneous; 63import com.sun.tools.javac.tree.DCTree.DCHidden; 64import com.sun.tools.javac.tree.DCTree.DCIdentifier; 65import com.sun.tools.javac.tree.DCTree.DCIndex; 66import com.sun.tools.javac.tree.DCTree.DCInheritDoc; 67import com.sun.tools.javac.tree.DCTree.DCLink; 68import com.sun.tools.javac.tree.DCTree.DCLiteral; 69import com.sun.tools.javac.tree.DCTree.DCParam; 70import com.sun.tools.javac.tree.DCTree.DCReference; 71import com.sun.tools.javac.tree.DCTree.DCReturn; 72import com.sun.tools.javac.tree.DCTree.DCSee; 73import com.sun.tools.javac.tree.DCTree.DCSerial; 74import com.sun.tools.javac.tree.DCTree.DCSerialData; 75import com.sun.tools.javac.tree.DCTree.DCSerialField; 76import com.sun.tools.javac.tree.DCTree.DCSince; 77import com.sun.tools.javac.tree.DCTree.DCStartElement; 78import com.sun.tools.javac.tree.DCTree.DCText; 79import com.sun.tools.javac.tree.DCTree.DCThrows; 80import com.sun.tools.javac.tree.DCTree.DCUnknownBlockTag; 81import com.sun.tools.javac.tree.DCTree.DCUnknownInlineTag; 82import com.sun.tools.javac.tree.DCTree.DCValue; 83import com.sun.tools.javac.tree.DCTree.DCVersion; 84import com.sun.tools.javac.util.Context; 85import com.sun.tools.javac.util.DefinedBy; 86import com.sun.tools.javac.util.DefinedBy.Api; 87import com.sun.tools.javac.util.DiagnosticSource; 88import com.sun.tools.javac.util.JCDiagnostic; 89import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 90import com.sun.tools.javac.util.ListBuffer; 91import com.sun.tools.javac.util.Pair; 92import com.sun.tools.javac.util.Position; 93 94import static com.sun.tools.doclint.HtmlTag.*; 95 96/** 97 * 98 * <p><b>This is NOT part of any supported API. 99 * If you write code that depends on this, you do so at your own risk. 100 * This code and its internal interfaces are subject to change or 101 * deletion without notice.</b> 102 */ 103public class DocTreeMaker implements DocTreeFactory { 104 105 /** The context key for the tree factory. */ 106 protected static final Context.Key<DocTreeMaker> treeMakerKey = new Context.Key<>(); 107 108 // A subset of block tags, which acts as sentence breakers, appearing 109 // anywhere but the zero'th position in the first sentence. 110 final EnumSet<HtmlTag> sentenceBreakTags; 111 112 /** Get the TreeMaker instance. */ 113 public static DocTreeMaker instance(Context context) { 114 DocTreeMaker instance = context.get(treeMakerKey); 115 if (instance == null) 116 instance = new DocTreeMaker(context); 117 return instance; 118 } 119 120 /** The position at which subsequent trees will be created. 121 */ 122 public int pos = Position.NOPOS; 123 124 /** Access to diag factory for ErroneousTrees. */ 125 private final JCDiagnostic.Factory diags; 126 127 private final JavacTrees trees; 128 129 /** Utility class to parse reference signatures. */ 130 private final ReferenceParser referenceParser; 131 132 /** Create a tree maker with NOPOS as initial position. 133 */ 134 protected DocTreeMaker(Context context) { 135 context.put(treeMakerKey, this); 136 diags = JCDiagnostic.Factory.instance(context); 137 this.pos = Position.NOPOS; 138 trees = JavacTrees.instance(context); 139 referenceParser = new ReferenceParser(ParserFactory.instance(context)); 140 sentenceBreakTags = EnumSet.of(H1, H2, H3, H4, H5, H6, PRE, P); 141 } 142 143 /** Reassign current position. 144 */ 145 @Override @DefinedBy(Api.COMPILER_TREE) 146 public DocTreeMaker at(int pos) { 147 this.pos = pos; 148 return this; 149 } 150 151 /** Reassign current position. 152 */ 153 public DocTreeMaker at(DiagnosticPosition pos) { 154 this.pos = (pos == null ? Position.NOPOS : pos.getStartPosition()); 155 return this; 156 } 157 158 @Override @DefinedBy(Api.COMPILER_TREE) 159 public DCAttribute newAttributeTree(javax.lang.model.element.Name name, ValueKind vkind, java.util.List<? extends DocTree> value) { 160 DCAttribute tree = new DCAttribute(name, vkind, cast(value)); 161 tree.pos = pos; 162 return tree; 163 } 164 165 @Override @DefinedBy(Api.COMPILER_TREE) 166 public DCAuthor newAuthorTree(java.util.List<? extends DocTree> name) { 167 DCAuthor tree = new DCAuthor(cast(name)); 168 tree.pos = pos; 169 return tree; 170 } 171 172 @Override @DefinedBy(Api.COMPILER_TREE) 173 public DCLiteral newCodeTree(TextTree text) { 174 DCLiteral tree = new DCLiteral(Kind.CODE, (DCText) text); 175 tree.pos = pos; 176 return tree; 177 } 178 179 @Override @DefinedBy(Api.COMPILER_TREE) 180 public DCComment newCommentTree(String text) { 181 DCComment tree = new DCComment(text); 182 tree.pos = pos; 183 return tree; 184 } 185 186 @Override @DefinedBy(Api.COMPILER_TREE) 187 public DCDeprecated newDeprecatedTree(List<? extends DocTree> text) { 188 DCDeprecated tree = new DCDeprecated(cast(text)); 189 tree.pos = pos; 190 return tree; 191 } 192 193 public DCDocComment newDocCommentTree(Comment comment, List<? extends DocTree> fullBody, List<? extends DocTree> tags) { 194 Pair<List<DCTree>, List<DCTree>> pair = splitBody(fullBody); 195 DCDocComment tree = new DCDocComment(comment, cast(fullBody), pair.fst, pair.snd, cast(tags)); 196 tree.pos = pos; 197 return tree; 198 } 199 200 /* 201 * Primarily to produce a DocCommenTree when given a 202 * first sentence and a body, this is useful, in cases 203 * where the trees are being synthesized by a tool. 204 */ 205 @Override @DefinedBy(Api.COMPILER_TREE) 206 public DCDocComment newDocCommentTree(List<? extends DocTree> firstSentence, List<? extends DocTree> body, List<? extends DocTree> tags) { 207 ListBuffer<DCTree> lb = new ListBuffer<>(); 208 lb.addAll(cast(firstSentence)); 209 lb.addAll(cast(body)); 210 List<DCTree> fullBody = lb.toList(); 211 212 // A dummy comment to keep the diagnostics logic happy. 213 Comment c = new Comment() { 214 @Override 215 public String getText() { 216 return null; 217 } 218 219 @Override 220 public int getSourcePos(int index) { 221 return Position.NOPOS; 222 } 223 224 @Override 225 public CommentStyle getStyle() { 226 return CommentStyle.JAVADOC; 227 } 228 229 @Override 230 public boolean isDeprecated() { 231 return false; 232 } 233 }; 234 235 DCDocComment tree = new DCDocComment(c, fullBody, cast(firstSentence), cast(body), cast(tags)); 236 return tree; 237 } 238 239 @Override @DefinedBy(Api.COMPILER_TREE) 240 public DCDocRoot newDocRootTree() { 241 DCDocRoot tree = new DCDocRoot(); 242 tree.pos = pos; 243 return tree; 244 } 245 246 @Override @DefinedBy(Api.COMPILER_TREE) 247 public DCEndElement newEndElementTree(Name name) { 248 DCEndElement tree = new DCEndElement(name); 249 tree.pos = pos; 250 return tree; 251 } 252 253 @Override @DefinedBy(Api.COMPILER_TREE) 254 public DCEntity newEntityTree(Name name) { 255 DCEntity tree = new DCEntity(name); 256 tree.pos = pos; 257 return tree; 258 } 259 260 @Override @DefinedBy(Api.COMPILER_TREE) 261 public DCErroneous newErroneousTree(String text, Diagnostic<JavaFileObject> diag) { 262 DCErroneous tree = new DCErroneous(text, (JCDiagnostic) diag); 263 tree.pos = pos; 264 return tree; 265 } 266 267 public DCErroneous newErroneousTree(String text, DiagnosticSource diagSource, String code, Object... args) { 268 DCErroneous tree = new DCErroneous(text, diags, diagSource, code, args); 269 tree.pos = pos; 270 return tree; 271 } 272 273 @Override @DefinedBy(Api.COMPILER_TREE) 274 public DCThrows newExceptionTree(ReferenceTree name, List<? extends DocTree> description) { 275 // TODO: verify the reference is just to a type (not a field or method) 276 DCThrows tree = new DCThrows(Kind.EXCEPTION, (DCReference) name, cast(description)); 277 tree.pos = pos; 278 return tree; 279 } 280 281 @Override @DefinedBy(Api.COMPILER_TREE) 282 public DCHidden newHiddenTree(List<? extends DocTree> text) { 283 DCHidden tree = new DCHidden(cast(text)); 284 tree.pos = pos; 285 return tree; 286 } 287 288 @Override @DefinedBy(Api.COMPILER_TREE) 289 public DCIdentifier newIdentifierTree(Name name) { 290 DCIdentifier tree = new DCIdentifier(name); 291 tree.pos = pos; 292 return tree; 293 } 294 295 @Override @DefinedBy(Api.COMPILER_TREE) 296 public DCIndex newIndexTree(DocTree term, List<? extends DocTree> description) { 297 DCIndex tree = new DCIndex((DCTree) term, cast(description)); 298 tree.pos = pos; 299 return tree; 300 } 301 302 @Override @DefinedBy(Api.COMPILER_TREE) 303 public DCInheritDoc newInheritDocTree() { 304 DCInheritDoc tree = new DCInheritDoc(); 305 tree.pos = pos; 306 return tree; 307 } 308 309 @Override @DefinedBy(Api.COMPILER_TREE) 310 public DCLink newLinkTree(ReferenceTree ref, List<? extends DocTree> label) { 311 DCLink tree = new DCLink(Kind.LINK, (DCReference) ref, cast(label)); 312 tree.pos = pos; 313 return tree; 314 } 315 316 @Override @DefinedBy(Api.COMPILER_TREE) 317 public DCLink newLinkPlainTree(ReferenceTree ref, List<? extends DocTree> label) { 318 DCLink tree = new DCLink(Kind.LINK_PLAIN, (DCReference) ref, cast(label)); 319 tree.pos = pos; 320 return tree; 321 } 322 323 @Override @DefinedBy(Api.COMPILER_TREE) 324 public DCLiteral newLiteralTree(TextTree text) { 325 DCLiteral tree = new DCLiteral(Kind.LITERAL, (DCText) text); 326 tree.pos = pos; 327 return tree; 328 } 329 330 @Override @DefinedBy(Api.COMPILER_TREE) 331 public DCParam newParamTree(boolean isTypeParameter, IdentifierTree name, List<? extends DocTree> description) { 332 DCParam tree = new DCParam(isTypeParameter, (DCIdentifier) name, cast(description)); 333 tree.pos = pos; 334 return tree; 335 } 336 337 @Override @DefinedBy(Api.COMPILER_TREE) 338 public DCReference newReferenceTree(String signature) { 339 try { 340 ReferenceParser.Reference ref = referenceParser.parse(signature); 341 DCReference tree = new DCReference(signature, ref.qualExpr, ref.member, ref.paramTypes); 342 tree.pos = pos; 343 return tree; 344 } catch (ReferenceParser.ParseException e) { 345 throw new IllegalArgumentException("invalid signature", e); 346 } 347 } 348 349 public DCReference newReferenceTree(String signature, JCTree qualExpr, Name member, List<JCTree> paramTypes) { 350 DCReference tree = new DCReference(signature, qualExpr, member, paramTypes); 351 tree.pos = pos; 352 return tree; 353 } 354 355 @Override @DefinedBy(Api.COMPILER_TREE) 356 public DCReturn newReturnTree(List<? extends DocTree> description) { 357 DCReturn tree = new DCReturn(cast(description)); 358 tree.pos = pos; 359 return tree; 360 } 361 362 @Override @DefinedBy(Api.COMPILER_TREE) 363 public DCSee newSeeTree(List<? extends DocTree> reference) { 364 DCSee tree = new DCSee(cast(reference)); 365 tree.pos = pos; 366 return tree; 367 } 368 369 @Override @DefinedBy(Api.COMPILER_TREE) 370 public DCSerial newSerialTree(List<? extends DocTree> description) { 371 DCSerial tree = new DCSerial(cast(description)); 372 tree.pos = pos; 373 return tree; 374 } 375 376 @Override @DefinedBy(Api.COMPILER_TREE) 377 public DCSerialData newSerialDataTree(List<? extends DocTree> description) { 378 DCSerialData tree = new DCSerialData(cast(description)); 379 tree.pos = pos; 380 return tree; 381 } 382 383 @Override @DefinedBy(Api.COMPILER_TREE) 384 public DCSerialField newSerialFieldTree(IdentifierTree name, ReferenceTree type, List<? extends DocTree> description) { 385 DCSerialField tree = new DCSerialField((DCIdentifier) name, (DCReference) type, cast(description)); 386 tree.pos = pos; 387 return tree; 388 } 389 390 @Override @DefinedBy(Api.COMPILER_TREE) 391 public DCSince newSinceTree(List<? extends DocTree> text) { 392 DCSince tree = new DCSince(cast(text)); 393 tree.pos = pos; 394 return tree; 395 } 396 397 @Override @DefinedBy(Api.COMPILER_TREE) 398 public DCStartElement newStartElementTree(Name name, List<? extends DocTree> attrs, boolean selfClosing) { 399 DCStartElement tree = new DCStartElement(name, cast(attrs), selfClosing); 400 tree.pos = pos; 401 return tree; 402 } 403 404 @Override @DefinedBy(Api.COMPILER_TREE) 405 public DCText newTextTree(String text) { 406 DCText tree = new DCText(text); 407 tree.pos = pos; 408 return tree; 409 } 410 411 @Override @DefinedBy(Api.COMPILER_TREE) 412 public DCThrows newThrowsTree(ReferenceTree name, List<? extends DocTree> description) { 413 // TODO: verify the reference is just to a type (not a field or method) 414 DCThrows tree = new DCThrows(Kind.THROWS, (DCReference) name, cast(description)); 415 tree.pos = pos; 416 return tree; 417 } 418 419 @Override @DefinedBy(Api.COMPILER_TREE) 420 public DCUnknownBlockTag newUnknownBlockTagTree(Name name, List<? extends DocTree> content) { 421 DCUnknownBlockTag tree = new DCUnknownBlockTag(name, cast(content)); 422 tree.pos = pos; 423 return tree; 424 } 425 426 @Override @DefinedBy(Api.COMPILER_TREE) 427 public DCUnknownInlineTag newUnknownInlineTagTree(Name name, List<? extends DocTree> content) { 428 DCUnknownInlineTag tree = new DCUnknownInlineTag(name, cast(content)); 429 tree.pos = pos; 430 return tree; 431 } 432 433 @Override @DefinedBy(Api.COMPILER_TREE) 434 public DCValue newValueTree(ReferenceTree ref) { 435 // TODO: verify the reference is to a constant value 436 DCValue tree = new DCValue((DCReference) ref); 437 tree.pos = pos; 438 return tree; 439 } 440 441 @Override @DefinedBy(Api.COMPILER_TREE) 442 public DCVersion newVersionTree(List<? extends DocTree> text) { 443 DCVersion tree = new DCVersion(cast(text)); 444 tree.pos = pos; 445 return tree; 446 } 447 448 @Override @DefinedBy(Api.COMPILER_TREE) 449 public java.util.List<DocTree> getFirstSentence(java.util.List<? extends DocTree> list) { 450 Pair<List<DCTree>, List<DCTree>> pair = splitBody(list); 451 return new ArrayList<>(pair.fst); 452 } 453 454 /* 455 * Breaks up the body tags into the first sentence and its successors. 456 * The first sentence is determined with the presence of a period, 457 * block tag, or a sentence break, as returned by the BreakIterator. 458 * Trailing whitespaces are trimmed. 459 */ 460 private Pair<List<DCTree>, List<DCTree>> splitBody(Collection<? extends DocTree> list) { 461 // pos is modified as we create trees, therefore 462 // we save the pos and restore it later. 463 final int savedpos = this.pos; 464 try { 465 ListBuffer<DCTree> body = new ListBuffer<>(); 466 // split body into first sentence and body 467 ListBuffer<DCTree> fs = new ListBuffer<>(); 468 if (list.isEmpty()) { 469 return new Pair<>(fs.toList(), body.toList()); 470 } 471 boolean foundFirstSentence = false; 472 ArrayList<DocTree> alist = new ArrayList<>(list); 473 ListIterator<DocTree> itr = alist.listIterator(); 474 while (itr.hasNext()) { 475 boolean isFirst = !itr.hasPrevious(); 476 DocTree dt = itr.next(); 477 int spos = ((DCTree) dt).pos; 478 if (foundFirstSentence) { 479 body.add((DCTree) dt); 480 continue; 481 } 482 switch (dt.getKind()) { 483 case TEXT: 484 DCText tt = (DCText) dt; 485 String s = tt.getBody(); 486 DocTree peekedNext = itr.hasNext() 487 ? alist.get(itr.nextIndex()) 488 : null; 489 int sbreak = getSentenceBreak(s, peekedNext); 490 if (sbreak > 0) { 491 s = removeTrailingWhitespace(s.substring(0, sbreak)); 492 DCText text = this.at(spos).newTextTree(s); 493 fs.add(text); 494 foundFirstSentence = true; 495 int nwPos = skipWhiteSpace(tt.getBody(), sbreak); 496 if (nwPos > 0) { 497 DCText text2 = this.at(spos + nwPos).newTextTree(tt.getBody().substring(nwPos)); 498 body.add(text2); 499 } 500 continue; 501 } else if (itr.hasNext()) { 502 // if the next doctree is a break, remove trailing spaces 503 peekedNext = alist.get(itr.nextIndex()); 504 boolean sbrk = isSentenceBreak(peekedNext, false); 505 if (sbrk) { 506 DocTree next = itr.next(); 507 s = removeTrailingWhitespace(s); 508 DCText text = this.at(spos).newTextTree(s); 509 fs.add(text); 510 body.add((DCTree) next); 511 foundFirstSentence = true; 512 continue; 513 } 514 } 515 break; 516 default: 517 if (isSentenceBreak(dt, isFirst)) { 518 body.add((DCTree) dt); 519 foundFirstSentence = true; 520 continue; 521 } 522 break; 523 } 524 fs.add((DCTree) dt); 525 } 526 return new Pair<>(fs.toList(), body.toList()); 527 } finally { 528 this.pos = savedpos; 529 } 530 } 531 532 private boolean isTextTree(DocTree tree) { 533 return tree.getKind() == Kind.TEXT; 534 } 535 536 /* 537 * Computes the first sentence break, a simple dot-space algorithm. 538 */ 539 private int defaultSentenceBreak(String s) { 540 // scan for period followed by whitespace 541 int period = -1; 542 for (int i = 0; i < s.length(); i++) { 543 switch (s.charAt(i)) { 544 case '.': 545 period = i; 546 break; 547 548 case ' ': 549 case '\f': 550 case '\n': 551 case '\r': 552 case '\t': 553 if (period >= 0) { 554 return i; 555 } 556 break; 557 558 default: 559 period = -1; 560 break; 561 } 562 } 563 return -1; 564 } 565 566 /* 567 * Computes the first sentence, if using a default breaker, 568 * the break is returned, if not then a -1, indicating that 569 * more doctree elements are required to be examined. 570 * 571 * BreakIterator.next points to the the start of the following sentence, 572 * and does not provide an easy way to disambiguate between "sentence break", 573 * "possible sentence break" and "not a sentence break" at the end of the input. 574 * For example, BreakIterator.next returns the index for the end 575 * of the string for all of these examples, 576 * using vertical bars to delimit the bounds of the example text 577 * |Abc| (not a valid end of sentence break, if followed by more text) 578 * |Abc.| (maybe a valid end of sentence break, depending on the following text) 579 * |Abc. | (maybe a valid end of sentence break, depending on the following text) 580 * |"Abc." | (maybe a valid end of sentence break, depending on the following text) 581 * |Abc. | (definitely a valid end of sentence break) 582 * |"Abc." | (definitely a valid end of sentence break) 583 * Therefore, we have to probe further to determine whether 584 * there really is a sentence break or not at the end of this run of text. 585 */ 586 private int getSentenceBreak(String s, DocTree dt) { 587 BreakIterator breakIterator = trees.getBreakIterator(); 588 if (breakIterator == null) { 589 return defaultSentenceBreak(s); 590 } 591 breakIterator.setText(s); 592 final int sbrk = breakIterator.next(); 593 // This is the last doctree, found the droid we are looking for 594 if (dt == null) { 595 return sbrk; 596 } 597 598 // If the break is well within the span of the string ie. not 599 // at EOL, then we have a clear break. 600 if (sbrk < s.length() - 1) { 601 return sbrk; 602 } 603 604 if (isTextTree(dt)) { 605 // Two adjacent text trees, a corner case, perhaps 606 // produced by a tool synthesizing a doctree. In 607 // this case, does the break lie within the first span, 608 // then we have the droid, otherwise allow the callers 609 // logic to handle the break in the adjacent doctree. 610 TextTree ttnext = (TextTree) dt; 611 String combined = s + ttnext.getBody(); 612 breakIterator.setText(combined); 613 int sbrk2 = breakIterator.next(); 614 if (sbrk < sbrk2) { 615 return sbrk; 616 } 617 } 618 619 // Is the adjacent tree a sentence breaker ? 620 if (isSentenceBreak(dt, false)) { 621 return sbrk; 622 } 623 624 // At this point the adjacent tree is either a javadoc tag ({@..), 625 // html tag (<..) or an entity (&..). Perform a litmus test, by 626 // concatenating a sentence, to validate the break earlier identified. 627 String combined = s + "Dummy Sentence."; 628 breakIterator.setText(combined); 629 int sbrk2 = breakIterator.next(); 630 if (sbrk2 <= sbrk) { 631 return sbrk2; 632 } 633 return -1; // indeterminate at this time 634 } 635 636 private boolean isSentenceBreak(javax.lang.model.element.Name tagName) { 637 return sentenceBreakTags.contains(get(tagName)); 638 } 639 640 private boolean isSentenceBreak(DocTree dt, boolean isFirstDocTree) { 641 switch (dt.getKind()) { 642 case START_ELEMENT: 643 StartElementTree set = (StartElementTree)dt; 644 return !isFirstDocTree && ((DCTree) dt).pos > 1 && isSentenceBreak(set.getName()); 645 case END_ELEMENT: 646 EndElementTree eet = (EndElementTree)dt; 647 return !isFirstDocTree && ((DCTree) dt).pos > 1 && isSentenceBreak(eet.getName()); 648 default: 649 return false; 650 } 651 } 652 653 /* 654 * Returns the position of the the first non-white space 655 */ 656 private int skipWhiteSpace(String s, int start) { 657 for (int i = start; i < s.length(); i++) { 658 char c = s.charAt(i); 659 if (!Character.isWhitespace(c)) { 660 return i; 661 } 662 } 663 return -1; 664 } 665 666 private String removeTrailingWhitespace(String s) { 667 for (int i = s.length() - 1 ; i >= 0 ; i--) { 668 char ch = s.charAt(i); 669 if (!Character.isWhitespace(ch)) { 670 return s.substring(0, i + 1); 671 } 672 } 673 return s; 674 } 675 676 @SuppressWarnings("unchecked") 677 private List<DCTree> cast(List<? extends DocTree> list) { 678 return (List<DCTree>) list; 679 } 680} 681