Getting the java8 compiler remember the comments

This commit is contained in:
Roel Spilker committed 2013-08-13 00:24:51 +02:00
1 parent 2b393ec622
commit 132d603dd4
11 files changed
+320 -469

No files matched your search

@@ -20,6 +20,9 @@ public class Scanner implements Lexer {
protected Scanner(ScannerFactory fac, char[] input, int inputLength) {
}
protected Scanner(ScannerFactory fac, JavaTokenizer tokenizer) {
}
public static class Factory {
public static final Context.Key<Scanner.Factory> scannerFactoryKey = null;
+10 -4
View File
@@ -64,10 +64,13 @@ public class CommentCatcher {
private static void registerCommentsCollectingScannerFactory(Context context) {
try {
Class<?> scannerFactory;
if (Javac.getJavaCompilerVersion() <= 6) {
int javaCompilerVersion = Javac.getJavaCompilerVersion();
if (javaCompilerVersion <= 6) {
scannerFactory = Class.forName("lombok.javac.java6.CommentCollectingScannerFactory");
} else {
} else if (javaCompilerVersion == 7) {
scannerFactory = Class.forName("lombok.javac.java7.CommentCollectingScannerFactory");
} else {
scannerFactory = Class.forName("lombok.javac.java8.CommentCollectingScannerFactory");
}
scannerFactory.getMethod("preRegister", Context.class).invoke(null, context);
} catch (InvocationTargetException e) {
@@ -80,10 +83,13 @@ public class CommentCatcher {
private static void setInCompiler(JavaCompiler compiler, Context context, Map<JCCompilationUnit, List<CommentInfo>> commentsMap) {
try {
Class<?> parserFactory;
if (Javac.getJavaCompilerVersion() <= 6) {
int javaCompilerVersion = Javac.getJavaCompilerVersion();
if (javaCompilerVersion <= 6) {
parserFactory = Class.forName("lombok.javac.java6.CommentCollectingParserFactory");
} else {
} else if (javaCompilerVersion == 7) {
parserFactory = Class.forName("lombok.javac.java7.CommentCollectingParserFactory");
} else {
parserFactory = Class.forName("lombok.javac.java8.CommentCollectingParserFactory");
}
parserFactory.getMethod("setInCompiler", JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap);
} catch (InvocationTargetException e) {
@@ -27,10 +27,11 @@ import lombok.javac.CommentInfo;
import lombok.javac.CommentInfo.EndConnection;
import lombok.javac.CommentInfo.StartConnection;
import com.sun.tools.javac.parser.Scanner;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
public class CommentCollectingScanner extends DocCommentScanner {
public class CommentCollectingScanner extends Scanner {
private final ListBuffer<CommentInfo> comments = ListBuffer.lb();
private int endComment = 0;
@@ -26,7 +26,7 @@ import java.nio.CharBuffer;
import com.sun.tools.javac.parser.Scanner;
import com.sun.tools.javac.util.Context;
public class CommentCollectingScannerFactory extends DocCommentScanner.Factory {
public class CommentCollectingScannerFactory extends Scanner.Factory {
@SuppressWarnings("all")
public static void preRegister(final Context context) {
@@ -1,461 +0,0 @@
package lombok.javac.java6;
/*
* Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
import static com.sun.tools.javac.util.LayoutCharacters.*;
import java.nio.CharBuffer;
import com.sun.tools.javac.parser.Scanner;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Position;
/** An extension to the base lexical analyzer that captures
* and processes the contents of doc comments. It does so by
* translating Unicode escape sequences and by stripping the
* leading whitespace and starts from each line of the comment.
*
* <p><b>This is NOT part of any API supported by Sun Microsystems. If
* you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class DocCommentScanner extends Scanner {
/** A factory for creating scanners. */
public static class Factory extends Scanner.Factory {
@SuppressWarnings({"unchecked", "all"})
public static void preRegister(final Context context) {
context.put(scannerFactoryKey, new Context.Factory() {
public Object make() {
return new Factory(context);
}
public Object make(Context c) {
return new Factory(c);
}
});
}
/** Create a new scanner factory. */
protected Factory(Context context) {
super(context);
}
@Override
public Scanner newScanner(CharSequence input) {
if (input instanceof CharBuffer) {
return new DocCommentScanner(this, (CharBuffer)input);
} else {
char[] array = input.toString().toCharArray();
return newScanner(array, array.length);
}
}
@Override
public Scanner newScanner(char[] input, int inputLength) {
return new DocCommentScanner(this, input, inputLength);
}
}
/** Create a scanner from the input buffer. buffer must implement
* array() and compact(), and remaining() must be less than limit().
*/
protected DocCommentScanner(Factory fac, CharBuffer buffer) {
super(fac, buffer);
}
/** Create a scanner from the input array. The array must have at
* least a single character of extra space.
*/
protected DocCommentScanner(Factory fac, char[] input, int inputLength) {
super(fac, input, inputLength);
}
/** Starting position of the comment in original source
*/
private int pos;
/** The comment input buffer, index of next chacter to be read,
* index of one past last character in buffer.
*/
private char[] buf;
private int bp;
private int buflen;
/** The current character.
*/
private char ch;
/** The column number position of the current character.
*/
private int col;
/** The buffer index of the last converted Unicode character
*/
private int unicodeConversionBp = 0;
/**
* Buffer for doc comment.
*/
private char[] docCommentBuffer = new char[1024];
/**
* Number of characters in doc comment buffer.
*/
private int docCommentCount;
/**
* Translated and stripped contents of doc comment
*/
private String docComment = null;
/** Unconditionally expand the comment buffer.
*/
private void expandCommentBuffer() {
char[] newBuffer = new char[docCommentBuffer.length * 2];
System.arraycopy(docCommentBuffer, 0, newBuffer,
0, docCommentBuffer.length);
docCommentBuffer = newBuffer;
}
/** Convert an ASCII digit from its base (8, 10, or 16)
* to its value.
*/
private int digit(int base) {
char c = ch;
int result = Character.digit(c, base);
if (result >= 0 && c > 0x7f) {
ch = "0123456789abcdef".charAt(result);
}
return result;
}
/** Convert Unicode escape; bp points to initial '\' character
* (Spec 3.3).
*/
private void convertUnicode() {
if (ch == '\\' && unicodeConversionBp != bp) {
bp++; ch = buf[bp]; col++;
if (ch == 'u') {
do {
bp++; ch = buf[bp]; col++;
} while (ch == 'u');
int limit = bp + 3;
if (limit < buflen) {
int d = digit(16);
int code = d;
while (bp < limit && d >= 0) {
bp++; ch = buf[bp]; col++;
d = digit(16);
code = (code << 4) + d;
}
if (d >= 0) {
ch = (char)code;
unicodeConversionBp = bp;
return;
}
}
// "illegal.Unicode.esc", reported by base scanner
} else {
bp--;
ch = '\\';
col--;
}
}
}
/** Read next character.
*/
private void scanChar() {
bp++;
ch = buf[bp];
switch (ch) {
case '\r': // return
col = 0;
break;
case '\n': // newline
if (bp == 0 || buf[bp-1] != '\r') {
col = 0;
}
break;
case '\t': // tab
col = (col / TabInc * TabInc) + TabInc;
break;
case '\\': // possible Unicode
col++;
convertUnicode();
break;
default:
col++;
break;
}
}
/**
* Read next character in doc comment, skipping over double '\' characters.
* If a double '\' is skipped, put in the buffer and update buffer count.
*/
private void scanDocCommentChar() {
scanChar();
if (ch == '\\') {
if (buf[bp+1] == '\\' && unicodeConversionBp != bp) {
if (docCommentCount == docCommentBuffer.length)
expandCommentBuffer();
docCommentBuffer[docCommentCount++] = ch;
bp++; col++;
} else {
convertUnicode();
}
}
}
/* Reset doc comment before reading each new token
*/
public void nextToken() {
docComment = null;
super.nextToken();
}
/**
* Returns the documentation string of the current token.
*/
public String docComment() {
return docComment;
}
/**
* Process a doc comment and make the string content available.
* Strips leading whitespace and stars.
*/
@SuppressWarnings("fallthrough")
protected void processComment(CommentStyle style) {
if (style != CommentStyle.JAVADOC) {
return;
}
pos = pos();
buf = getRawCharacters(pos, endPos());
buflen = buf.length;
bp = 0;
col = 0;
docCommentCount = 0;
boolean firstLine = true;
// Skip over first slash
scanDocCommentChar();
// Skip over first star
scanDocCommentChar();
// consume any number of stars
while (bp < buflen && ch == '*') {
scanDocCommentChar();
}
// is the comment in the form /**/, /***/, /****/, etc. ?
if (bp < buflen && ch == '/') {
docComment = "";
return;
}
// skip a newline on the first line of the comment.
if (bp < buflen) {
if (ch == LF) {
scanDocCommentChar();
firstLine = false;
} else if (ch == CR) {
scanDocCommentChar();
if (ch == LF) {
scanDocCommentChar();
firstLine = false;
}
}
}
outerLoop:
// The outerLoop processes the doc comment, looping once
// for each line. For each line, it first strips off
// whitespace, then it consumes any stars, then it
// puts the rest of the line into our buffer.
while (bp < buflen) {
// The wsLoop consumes whitespace from the beginning
// of each line.
wsLoop:
while (bp < buflen) {
switch(ch) {
case ' ':
scanDocCommentChar();
break;
case '\t':
col = ((col - 1) / TabInc * TabInc) + TabInc;
scanDocCommentChar();
break;
case FF:
col = 0;
scanDocCommentChar();
break;
// Treat newline at beginning of line (blank line, no star)
// as comment text. Old Javadoc compatibility requires this.
/*---------------------------------*
case CR: // (Spec 3.4)
scanDocCommentChar();
if (ch == LF) {
col = 0;
scanDocCommentChar();
}
break;
case LF: // (Spec 3.4)
scanDocCommentChar();
break;
*---------------------------------*/
default:
// we've seen something that isn't whitespace;
// jump out.
break wsLoop;
}
}
// Are there stars here? If so, consume them all
// and check for the end of comment.
if (ch == '*') {
// skip all of the stars
do {
scanDocCommentChar();
} while (ch == '*');
// check for the closing slash.
if (ch == '/') {
// We're done with the doc comment
// scanChar() and breakout.
break outerLoop;
}
} else if (! firstLine) {
//The current line does not begin with a '*' so we will indent it.
for (int i = 1; i < col; i++) {
if (docCommentCount == docCommentBuffer.length)
expandCommentBuffer();
docCommentBuffer[docCommentCount++] = ' ';
}
}
// The textLoop processes the rest of the characters
// on the line, adding them to our buffer.
textLoop:
while (bp < buflen) {
switch (ch) {
case '*':
// Is this just a star? Or is this the
// end of a comment?
scanDocCommentChar();
if (ch == '/') {
// This is the end of the comment,
// set ch and return our buffer.
break outerLoop;
}
// This is just an ordinary star. Add it to
// the buffer.
if (docCommentCount == docCommentBuffer.length)
expandCommentBuffer();
docCommentBuffer[docCommentCount++] = '*';
break;
case ' ':
case '\t':
if (docCommentCount == docCommentBuffer.length)
expandCommentBuffer();
docCommentBuffer[docCommentCount++] = ch;
scanDocCommentChar();
break;
case FF:
scanDocCommentChar();
break textLoop; // treat as end of line
case CR: // (Spec 3.4)
scanDocCommentChar();
if (ch != LF) {
// Canonicalize CR-only line terminator to LF
if (docCommentCount == docCommentBuffer.length)
expandCommentBuffer();
docCommentBuffer[docCommentCount++] = (char)LF;
break textLoop;
}
/* fall through to LF case */
case LF: // (Spec 3.4)
// We've seen a newline. Add it to our
// buffer and break out of this loop,
// starting fresh on a new line.
if (docCommentCount == docCommentBuffer.length)
expandCommentBuffer();
docCommentBuffer[docCommentCount++] = ch;
scanDocCommentChar();
break textLoop;
default:
// Add the character to our buffer.
if (docCommentCount == docCommentBuffer.length)
expandCommentBuffer();
docCommentBuffer[docCommentCount++] = ch;
scanDocCommentChar();
}
} // end textLoop
firstLine = false;
} // end outerLoop
if (docCommentCount > 0) {
int i = docCommentCount - 1;
trailLoop:
while (i > -1) {
switch (docCommentBuffer[i]) {
case '*':
i--;
break;
default:
break trailLoop;
}
}
docCommentCount = i + 1;
// Store the text of the doc comment
docComment = new String(docCommentBuffer, 0 , docCommentCount);
} else {
docComment = "";
}
}
/** Build a map for translating between line numbers and
* positions in the input.
*
* @return a LineMap */
public Position.LineMap getLineMap() {
char[] buf = getRawCharacters();
return Position.makeLineMap(buf, buf.length, true);
}
}
@@ -27,11 +27,11 @@ import lombok.javac.CommentInfo;
import lombok.javac.CommentInfo.EndConnection;
import lombok.javac.CommentInfo.StartConnection;
import com.sun.tools.javac.parser.Scanner;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.parser.DocCommentScanner;
public class CommentCollectingScanner extends DocCommentScanner {
public class CommentCollectingScanner extends Scanner {
private final ListBuffer<CommentInfo> comments = ListBuffer.lb();
private int endComment = 0;
@@ -0,0 +1,32 @@
package lombok.javac.java8;
import java.util.List;
import java.util.Map;
import lombok.javac.CommentInfo;
import com.sun.tools.javac.parser.JavacParser;
import com.sun.tools.javac.parser.Lexer;
import com.sun.tools.javac.parser.ParserFactory;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
class CommentCollectingParser extends JavacParser {
private final Map<JCCompilationUnit, List<CommentInfo>> commentsMap;
private final Lexer lexer;
protected CommentCollectingParser(ParserFactory fac, Lexer S,
boolean keepDocComments, boolean keepLineMap, boolean keepEndPositions, Map<JCCompilationUnit, List<CommentInfo>> commentsMap) {
super(fac, S, keepDocComments, keepLineMap, keepEndPositions);
lexer = S;
this.commentsMap = commentsMap;
}
public JCCompilationUnit parseCompilationUnit() {
JCCompilationUnit result = super.parseCompilationUnit();
if (lexer instanceof CommentCollectingScanner) {
List<CommentInfo> comments = ((CommentCollectingScanner)lexer).getComments();
commentsMap.put(result, comments);
}
return result;
}
}
@@ -0,0 +1,52 @@
package lombok.javac.java8;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import lombok.javac.CommentInfo;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.parser.JavacParser;
import com.sun.tools.javac.parser.Lexer;
import com.sun.tools.javac.parser.ParserFactory;
import com.sun.tools.javac.parser.ScannerFactory;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.util.Context;
public class CommentCollectingParserFactory extends ParserFactory {
private final Map<JCCompilationUnit, List<CommentInfo>> commentsMap;
private final Context context;
static Context.Key<ParserFactory> key() {
return parserFactoryKey;
}
protected CommentCollectingParserFactory(Context context, Map<JCCompilationUnit, List<CommentInfo>> commentsMap) {
super(context);
this.context = context;
this.commentsMap = commentsMap;
}
public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap) {
ScannerFactory scannerFactory = ScannerFactory.instance(context);
Lexer lexer = scannerFactory.newScanner(input, true);
Object x = new CommentCollectingParser(this, lexer, true, keepLineMap, keepEndPos, commentsMap);
return (JavacParser) x;
// CCP is based on a stub which extends nothing, but at runtime the stub is replaced with either
//javac6's EndPosParser which extends Parser, or javac8's JavacParser which implements Parser.
//Either way this will work out.
}
public static void setInCompiler(JavaCompiler compiler, Context context, Map<JCCompilationUnit, List<CommentInfo>> commentsMap) {
context.put(CommentCollectingParserFactory.key(), (ParserFactory)null);
Field field;
try {
field = JavaCompiler.class.getDeclaredField("parserFactory");
field.setAccessible(true);
field.set(compiler, new CommentCollectingParserFactory(context, commentsMap));
} catch (Exception e) {
throw new IllegalStateException("Could not set comment sensitive parser in the compiler", e);
}
}
}
@@ -0,0 +1,21 @@
package lombok.javac.java8;
import lombok.javac.CommentInfo;
import com.sun.tools.javac.parser.Scanner;
import com.sun.tools.javac.parser.ScannerFactory;
import com.sun.tools.javac.util.List;
public class CommentCollectingScanner extends Scanner {
private CommentCollectingTokenizer tokenizer;
public CommentCollectingScanner(ScannerFactory fac, CommentCollectingTokenizer tokenizer) {
super(fac, tokenizer);
this.tokenizer = tokenizer;
}
public List<CommentInfo> getComments() {
return tokenizer.getComments();
}
}
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2011-2013 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lombok.javac.java8;
import java.nio.CharBuffer;
import com.sun.tools.javac.parser.Scanner;
import com.sun.tools.javac.parser.ScannerFactory;
import com.sun.tools.javac.util.Context;
public class CommentCollectingScannerFactory extends ScannerFactory {
@SuppressWarnings("all")
public static void preRegister(final Context context) {
if (context.get(scannerFactoryKey) == null) {
// Careful! There is voodoo magic here!
//
// Context.Factory is parameterized. make() is for javac6 and below; make(Context) is for javac7 and up.
// this anonymous inner class definition is intentionally 'raw' - the return type of both 'make' methods is 'T',
// which means the compiler will only generate the correct "real" override method (with returntype Object, which is
// the lower bound for T, as a synthetic accessor for the make with returntype ScannerFactory) for that make method which
// is actually on the classpath (either make() for javac6-, or make(Context) for javac7+).
//
// We normally solve this issue via src/stubs, with BOTH make methods listed, but for some reason the presence of a stubbed out
// Context (or even a complete copy, it doesn't matter) results in a really strange eclipse bug, where any mention of any kind
// of com.sun.tools.javac.tree.TreeMaker in a source file disables ALL usage of 'go to declaration' and auto-complete in the entire
// source file.
//
// Thus, in short:
// * Do NOT parameterize the anonymous inner class literal.
// * Leave the return types as 'j.l.Object'.
// * Leave both make methods intact; deleting one has no effect on javac6- / javac7+, but breaks the other. Hard to test for.
// * Do not stub com.sun.tools.javac.util.Context or any of its inner types, like Factory.
@SuppressWarnings("all")
class MyFactory implements Context.Factory {
// This overrides the javac6- version of make.
public Object make() {
return new CommentCollectingScannerFactory(context);
}
// This overrides the javac7+ version.
public Object make(Context c) {
return new CommentCollectingScannerFactory(c);
}
}
@SuppressWarnings("unchecked") Context.Factory<ScannerFactory> factory = new MyFactory();
context.put(scannerFactoryKey, factory);
}
}
/** Create a new scanner factory. */
protected CommentCollectingScannerFactory(Context context) {
super(context);
}
@Override
public Scanner newScanner(CharSequence input, boolean keepDocComments) {
if (input instanceof CharBuffer) {
CharBuffer buf = (CharBuffer) input;
return new CommentCollectingScanner(this, new CommentCollectingTokenizer(this, buf));
}
char[] array = input.toString().toCharArray();
return newScanner(array, array.length, keepDocComments);
}
@Override
public Scanner newScanner(char[] input, int inputLength, boolean keepDocComments) {
return new CommentCollectingScanner(this, new CommentCollectingTokenizer(this, input, inputLength));
}
}
@@ -0,0 +1,108 @@
package lombok.javac.java8;
import java.nio.CharBuffer;
import lombok.javac.CommentInfo;
import lombok.javac.CommentInfo.EndConnection;
import lombok.javac.CommentInfo.StartConnection;
import com.sun.tools.javac.parser.JavaTokenizer;
import com.sun.tools.javac.parser.ScannerFactory;
import com.sun.tools.javac.parser.Tokens.Comment;
import com.sun.tools.javac.parser.Tokens.Token;
import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
import com.sun.tools.javac.parser.UnicodeReader;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
class CommentCollectingTokenizer extends JavaTokenizer {
private int prevEndPosition = 0;
private final ListBuffer<CommentInfo> comments = ListBuffer.lb();
private int endComment = 0;
CommentCollectingTokenizer(ScannerFactory fac, char[] buf, int inputLength) {
super(fac, new PositionUnicodeReader(fac, buf, inputLength));
}
CommentCollectingTokenizer(ScannerFactory fac, CharBuffer buf) {
super(fac, new PositionUnicodeReader(fac, buf));
}
@Override public Token readToken() {
Token token = super.readToken();
prevEndPosition = ((PositionUnicodeReader)reader).pos();
return token;
}
@Override
protected Comment processComment(int pos, int endPos, CommentStyle style) {
int prevEndPos = Math.max(prevEndPosition, endComment);
endComment = endPos;
String content = new String(reader.getRawCharacters(pos, endPos));
StartConnection start = determineStartConnection(prevEndPos, pos);
EndConnection end = determineEndConnection(endPos);
CommentInfo comment = new CommentInfo(prevEndPos, pos, endPos, content, start, end);
comments.append(comment);
return super.processComment(pos, endPos, style);
}
private EndConnection determineEndConnection(int pos) {
boolean first = true;
for (int i = pos;; i++) {
char c;
try {
c = reader.getRawCharacters(i, i + 1)[0];
} catch (IndexOutOfBoundsException e) {
c = '\n';
}
if (isNewLine(c)) {
return EndConnection.ON_NEXT_LINE;
}
if (Character.isWhitespace(c)) {
first = false;
continue;
}
return first ? EndConnection.DIRECT_AFTER_COMMENT : EndConnection.AFTER_COMMENT;
}
}
private StartConnection determineStartConnection(int from, int to) {
if (from == to) {
return StartConnection.DIRECT_AFTER_PREVIOUS;
}
char[] between = reader.getRawCharacters(from, to);
if (isNewLine(between[between.length - 1])) {
return StartConnection.START_OF_LINE;
}
for (char c : between) {
if (isNewLine(c)) {
return StartConnection.ON_NEXT_LINE;
}
}
return StartConnection.AFTER_PREVIOUS;
}
private boolean isNewLine(char c) {
return c == '\n' || c == '\r';
}
public List<CommentInfo> getComments() {
return comments.toList();
}
static class PositionUnicodeReader extends UnicodeReader {
protected PositionUnicodeReader(ScannerFactory sf, char[] input, int inputLength) {
super(sf, input, inputLength);
}
public PositionUnicodeReader(ScannerFactory sf, CharBuffer buffer) {
super(sf, buffer);
}
int pos() {
return bp;
}
}
}