1.1 --- a/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java Wed Jun 20 13:23:26 2012 -0700 1.2 +++ b/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java Thu Jun 21 13:22:21 2012 -0700 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -62,19 +62,54 @@ 1.11 @Override 1.12 protected Comment processComment(int pos, int endPos, CommentStyle style) { 1.13 char[] buf = reader.getRawCharacters(pos, endPos); 1.14 - return new JavadocComment(new ColReader(fac, buf, buf.length), style); 1.15 + return new JavadocComment(new DocReader(fac, buf, buf.length, pos), style); 1.16 } 1.17 1.18 /** 1.19 * This is a specialized version of UnicodeReader that keeps track of the 1.20 - * column position within a given character stream (used for Javadoc processing). 1.21 + * column position within a given character stream (used for Javadoc processing), 1.22 + * and which builds a table for mapping positions in the comment string to 1.23 + * positions in the source file. 1.24 */ 1.25 - static class ColReader extends UnicodeReader { 1.26 + static class DocReader extends UnicodeReader { 1.27 1.28 int col; 1.29 + int startPos; 1.30 1.31 - ColReader(ScannerFactory fac, char[] input, int inputLength) { 1.32 + /** 1.33 + * A buffer for building a table for mapping positions in {@link #sbuf} 1.34 + * to positions in the source buffer. 1.35 + * 1.36 + * The array is organized as a series of pairs of integers: the first 1.37 + * number in each pair specifies a position in the comment text, 1.38 + * the second number in each pair specifies the corresponding position 1.39 + * in the source buffer. The pairs are sorted in ascending order. 1.40 + * 1.41 + * Since the mapping function is generally continuous, with successive 1.42 + * positions in the string corresponding to successive positions in the 1.43 + * source buffer, the table only needs to record discontinuities in 1.44 + * the mapping. The values of intermediate positions can be inferred. 1.45 + * 1.46 + * Discontinuities may occur in a number of places: when a newline 1.47 + * is followed by whitespace and asterisks (which are ignored), 1.48 + * when a tab is expanded into spaces, and when unicode escapes 1.49 + * are used in the source buffer. 1.50 + * 1.51 + * Thus, to find the source position of any position, p, in the comment 1.52 + * string, find the index, i, of the pair whose string offset 1.53 + * ({@code pbuf[i] }) is closest to but not greater than p. Then, 1.54 + * {@code sourcePos(p) = pbuf[i+1] + (p - pbuf[i]) }. 1.55 + */ 1.56 + int[] pbuf = new int[128]; 1.57 + 1.58 + /** 1.59 + * The index of the next empty slot in the pbuf buffer. 1.60 + */ 1.61 + int pp = 0; 1.62 + 1.63 + DocReader(ScannerFactory fac, char[] input, int inputLength, int startPos) { 1.64 super(fac, input, inputLength); 1.65 + this.startPos = startPos; 1.66 } 1.67 1.68 @Override 1.69 @@ -147,19 +182,43 @@ 1.70 break; 1.71 } 1.72 } 1.73 + 1.74 + @Override 1.75 + public void putChar(char ch, boolean scan) { 1.76 + // At this point, bp is the position of the current character in buf, 1.77 + // and sp is the position in sbuf where this character will be put. 1.78 + // Record a new entry in pbuf if pbuf is empty or if sp and its 1.79 + // corresponding source position are not equidistant from the 1.80 + // corresponding values in the latest entry in the pbuf array. 1.81 + // (i.e. there is a discontinuity in the map function.) 1.82 + if ((pp == 0) 1.83 + || (sp - pbuf[pp - 2] != (startPos + bp) - pbuf[pp - 1])) { 1.84 + if (pp + 1 >= pbuf.length) { 1.85 + int[] new_pbuf = new int[pbuf.length * 2]; 1.86 + System.arraycopy(pbuf, 0, new_pbuf, 0, pbuf.length); 1.87 + pbuf = new_pbuf; 1.88 + } 1.89 + pbuf[pp] = sp; 1.90 + pbuf[pp + 1] = startPos + bp; 1.91 + pp += 2; 1.92 + } 1.93 + super.putChar(ch, scan); 1.94 + } 1.95 } 1.96 1.97 - protected class JavadocComment extends JavaTokenizer.BasicComment<ColReader> { 1.98 + protected class JavadocComment extends JavaTokenizer.BasicComment<DocReader> { 1.99 1.100 /** 1.101 * Translated and stripped contents of doc comment 1.102 */ 1.103 private String docComment = null; 1.104 + private int[] docPosns = null; 1.105 1.106 - JavadocComment(ColReader comment_reader, CommentStyle cs) { 1.107 - super(comment_reader, cs); 1.108 + JavadocComment(DocReader reader, CommentStyle cs) { 1.109 + super(reader, cs); 1.110 } 1.111 1.112 + @Override 1.113 public String getText() { 1.114 if (!scanned && cs == CommentStyle.JAVADOC) { 1.115 scanDocComment(); 1.116 @@ -168,6 +227,33 @@ 1.117 } 1.118 1.119 @Override 1.120 + public int getSourcePos(int pos) { 1.121 + // Binary search to find the entry for which the string index is 1.122 + // less than pos. Since docPosns is a list of pairs of integers 1.123 + // we must make sure the index is always even. 1.124 + // If we find an exact match for pos, the other item in the pair 1.125 + // gives the source pos; otherwise, compute the source position 1.126 + // relative to the best match found in the array. 1.127 + if (pos < 0 || pos >= docComment.length()) 1.128 + throw new StringIndexOutOfBoundsException(); 1.129 + if (docPosns == null) 1.130 + return -1; 1.131 + int start = 0; 1.132 + int end = docPosns.length; 1.133 + while (start < end - 2) { 1.134 + // find an even index midway between start and end 1.135 + int index = ((start + end) / 4) * 2; 1.136 + if (docPosns[index] < pos) 1.137 + start = index; 1.138 + else if (docPosns[index] == pos) 1.139 + return docPosns[index + 1]; 1.140 + else 1.141 + end = index; 1.142 + } 1.143 + return docPosns[start + 1] + (pos - docPosns[start]); 1.144 + } 1.145 + 1.146 + @Override 1.147 @SuppressWarnings("fallthrough") 1.148 protected void scanDocComment() { 1.149 try { 1.150 @@ -209,7 +295,8 @@ 1.151 // whitespace, then it consumes any stars, then it 1.152 // puts the rest of the line into our buffer. 1.153 while (comment_reader.bp < comment_reader.buflen) { 1.154 - 1.155 + int begin_bp = comment_reader.bp; 1.156 + char begin_ch = comment_reader.ch; 1.157 // The wsLoop consumes whitespace from the beginning 1.158 // of each line. 1.159 wsLoop: 1.160 @@ -263,10 +350,10 @@ 1.161 break outerLoop; 1.162 } 1.163 } else if (! firstLine) { 1.164 - //The current line does not begin with a '*' so we will indent it. 1.165 - for (int i = 1; i < comment_reader.col; i++) { 1.166 - comment_reader.putChar(' ', false); 1.167 - } 1.168 + // The current line does not begin with a '*' so we will 1.169 + // treat it as comment 1.170 + comment_reader.bp = begin_bp; 1.171 + comment_reader.ch = begin_ch; 1.172 } 1.173 // The textLoop processes the rest of the characters 1.174 // on the line, adding them to our buffer. 1.175 @@ -334,6 +421,8 @@ 1.176 1.177 // Store the text of the doc comment 1.178 docComment = comment_reader.chars(); 1.179 + docPosns = new int[comment_reader.pp]; 1.180 + System.arraycopy(comment_reader.pbuf, 0, docPosns, 0, docPosns.length); 1.181 } else { 1.182 docComment = ""; 1.183 }