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