diff options
author | Roel Spilker <r.spilker@gmail.com> | 2013-11-19 21:02:59 +0100 |
---|---|---|
committer | Roel Spilker <r.spilker@gmail.com> | 2013-11-19 21:02:59 +0100 |
commit | 78b2d6919e35887940f9f11b6ae1731245739b83 (patch) | |
tree | 0dc305883c19a862a38669374c5614e26480d4b8 /src/utils/lombok | |
parent | 5deb185591904d275cb06eea85c0d739587fc738 (diff) | |
parent | 83b7e77b0cce6cd5993b17f36164271accdd281c (diff) | |
download | lombok-78b2d6919e35887940f9f11b6ae1731245739b83.tar.gz lombok-78b2d6919e35887940f9f11b6ae1731245739b83.tar.bz2 lombok-78b2d6919e35887940f9f11b6ae1731245739b83.zip |
Merge branch 'master' of github.com:rzwitserloot/lombok
Conflicts:
src/delombok/lombok/delombok/DelombokApp.java
Diffstat (limited to 'src/utils/lombok')
18 files changed, 1624 insertions, 583 deletions
diff --git a/src/utils/lombok/core/debug/FileLog.java b/src/utils/lombok/core/debug/FileLog.java new file mode 100644 index 00000000..dedec40e --- /dev/null +++ b/src/utils/lombok/core/debug/FileLog.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 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.core.debug; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +public class FileLog { + private static FileOutputStream fos; + + public static void log(String message) { + log(message, null); + } + public synchronized static void log(String message, Throwable t) { + try { + if (fos == null) { + fos = new FileOutputStream(new File(System.getProperty("user.home"), "LOMBOK-DEBUG-OUT.txt")); + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + try { + fos.close(); + } catch (Throwable ignore) {} + } + }); + } + fos.write(message.getBytes("UTF-8")); + fos.write('\n'); + if (t != null) { + StringWriter sw = new StringWriter(); + t.printStackTrace(new PrintWriter(sw)); + fos.write(sw.toString().getBytes("UTF-8")); + fos.write('\n'); + } + fos.flush(); + } catch (IOException e) { + throw new IllegalStateException("Internal lombok file-based debugging not possible", e); + } + } +} diff --git a/src/utils/lombok/javac/CommentCatcher.java b/src/utils/lombok/javac/CommentCatcher.java index 565a166d..36d90e30 100644 --- a/src/utils/lombok/javac/CommentCatcher.java +++ b/src/utils/lombok/javac/CommentCatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Project Lombok Authors. + * 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 @@ -21,13 +21,15 @@ */ package lombok.javac; +import java.lang.reflect.InvocationTargetException; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.WeakHashMap; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.List; public class CommentCatcher { private final JavaCompiler compiler; @@ -55,38 +57,54 @@ public class CommentCatcher { return compiler; } + public void setComments(JCCompilationUnit ast, List<CommentInfo> comments) { + if (comments != null) { + commentsMap.put(ast, comments); + } else { + commentsMap.remove(ast); + } + } + public List<CommentInfo> getComments(JCCompilationUnit ast) { List<CommentInfo> list = commentsMap.get(ast); - return list == null ? List.<CommentInfo>nil() : list; + return list == null ? Collections.<CommentInfo>emptyList() : list; } private static void registerCommentsCollectingScannerFactory(Context context) { try { - if (Javac.getJavaCompilerVersion() <= 6) { - Class.forName("lombok.javac.java6.CommentCollectingScannerFactory").getMethod("preRegister", Context.class).invoke(null, context); + Class<?> scannerFactory; + int javaCompilerVersion = Javac.getJavaCompilerVersion(); + if (javaCompilerVersion <= 6) { + scannerFactory = Class.forName("lombok.javac.java6.CommentCollectingScannerFactory"); + } else if (javaCompilerVersion == 7) { + scannerFactory = Class.forName("lombok.javac.java7.CommentCollectingScannerFactory"); } else { - Class.forName("lombok.javac.java7.CommentCollectingScannerFactory").getMethod("preRegister", Context.class).invoke(null, context); + scannerFactory = Class.forName("lombok.javac.java8.CommentCollectingScannerFactory"); } + scannerFactory.getMethod("preRegister", Context.class).invoke(null, context); + } catch (InvocationTargetException e) { + throw Javac.sneakyThrow(e.getCause()); } catch (Exception e) { - if (e instanceof RuntimeException) throw (RuntimeException)e; - throw new RuntimeException(e); + throw Javac.sneakyThrow(e); } } private static void setInCompiler(JavaCompiler compiler, Context context, Map<JCCompilationUnit, List<CommentInfo>> commentsMap) { - try { - if (Javac.getJavaCompilerVersion() <= 6) { - Class<?> parserFactory = Class.forName("lombok.javac.java6.CommentCollectingParserFactory"); - parserFactory.getMethod("setInCompiler", JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); + Class<?> parserFactory; + int javaCompilerVersion = Javac.getJavaCompilerVersion(); + if (javaCompilerVersion <= 6) { + parserFactory = Class.forName("lombok.javac.java6.CommentCollectingParserFactory"); + } else if (javaCompilerVersion == 7) { + parserFactory = Class.forName("lombok.javac.java7.CommentCollectingParserFactory"); } else { - Class<?> parserFactory = Class.forName("lombok.javac.java7.CommentCollectingParserFactory"); - parserFactory.getMethod("setInCompiler", JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); + parserFactory = Class.forName("lombok.javac.java8.CommentCollectingParserFactory"); } + parserFactory.getMethod("setInCompiler", JavaCompiler.class, Context.class, Map.class).invoke(null, compiler, context, commentsMap); + } catch (InvocationTargetException e) { + throw Javac.sneakyThrow(e.getCause()); } catch (Exception e) { - if (e instanceof RuntimeException) throw (RuntimeException)e; - throw new RuntimeException(e); + throw Javac.sneakyThrow(e); } } - } diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index 4f316d9f..bdf5e7a0 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -21,57 +21,105 @@ */ package lombok.javac; +import static lombok.javac.JavacTreeMaker.TreeTag.treeTag; +import static lombok.javac.JavacTreeMaker.TypeTag.typeTag; + import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.sun.tools.javac.code.TypeTags; +import javax.lang.model.type.NoType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeVisitor; + +import lombok.javac.JavacTreeMaker.TreeTag; +import lombok.javac.JavacTreeMaker.TypeTag; + +import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.code.Type; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCLiteral; -import com.sun.tools.javac.tree.JCTree.JCModifiers; -import com.sun.tools.javac.tree.JCTree.JCTypeParameter; -import com.sun.tools.javac.tree.TreeMaker; -import com.sun.tools.javac.util.List; -import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; /** * Container for static utility methods relevant to lombok's operation on javac. */ public class Javac { private Javac() { - //prevent instantiation + // prevent instantiation } /** Matches any of the 8 primitive names, such as {@code boolean}. */ - private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile( - "^(boolean|byte|short|int|long|float|double|char)$"); + private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile("^(boolean|byte|short|int|long|float|double|char)$"); private static final Pattern VERSION_PARSER = Pattern.compile("^(\\d{1,6})\\.(\\d{1,6}).*$"); + private static final Pattern SOURCE_PARSER = Pattern.compile("^JDK(\\d{1,6})_(\\d{1,6}).*$"); + + private static final AtomicInteger compilerVersion = new AtomicInteger(-1); /** * Returns the version of this java compiler, i.e. the JDK that it shipped in. For example, for javac v1.7, this returns {@code 7}. */ public static int getJavaCompilerVersion() { - Matcher m = VERSION_PARSER.matcher(JavaCompiler.version()); - if (m.matches()) { - int major = Integer.parseInt(m.group(1)); - int minor = Integer.parseInt(m.group(2)); - if (major == 1) return minor; + int cv = compilerVersion.get(); + if (cv != -1) return cv; + + /* Main algorithm: Use JavaCompiler's intended method to do this */ { + Matcher m = VERSION_PARSER.matcher(JavaCompiler.version()); + if (m.matches()) { + int major = Integer.parseInt(m.group(1)); + int minor = Integer.parseInt(m.group(2)); + if (major == 1) { + compilerVersion.set(minor); + return minor; + } + } } + /* Fallback algorithm one: Check Source's values. Lets hope oracle never releases a javac that recognizes future versions for -source */ { + String name = Source.values()[Source.values().length - 1].name(); + Matcher m = SOURCE_PARSER.matcher(name); + if (m.matches()) { + int major = Integer.parseInt(m.group(1)); + int minor = Integer.parseInt(m.group(2)); + if (major == 1) { + compilerVersion.set(minor); + return minor; + } + } + } + + compilerVersion.set(6); return 6; } + private static final Class<?> DOCCOMMENTTABLE_CLASS; + + static { + Class<?> c = null; + try { + c = Class.forName("com.sun.tools.javac.tree.DocCommentTable"); + } catch (Throwable ignore) {} + DOCCOMMENTTABLE_CLASS = c; + } + + public static boolean instanceOfDocCommentTable(Object o) { + return DOCCOMMENTTABLE_CLASS != null && DOCCOMMENTTABLE_CLASS.isInstance(o); + } + /** - * Checks if the given expression (that really ought to refer to a type expression) represents a primitive type. + * Checks if the given expression (that really ought to refer to a type + * expression) represents a primitive type. */ public static boolean isPrimitive(JCExpression ref) { String typeName = ref.toString(); @@ -79,15 +127,16 @@ public class Javac { } /** - * Turns an expression into a guessed intended literal. Only works for literals, as you can imagine. + * Turns an expression into a guessed intended literal. Only works for + * literals, as you can imagine. * * Will for example turn a TrueLiteral into 'Boolean.valueOf(true)'. */ public static Object calculateGuess(JCExpression expr) { if (expr instanceof JCLiteral) { - JCLiteral lit = (JCLiteral)expr; + JCLiteral lit = (JCLiteral) expr; if (lit.getKind() == com.sun.source.tree.Tree.Kind.BOOLEAN_LITERAL) { - return ((Number)lit.value).intValue() == 0 ? false : true; + return ((Number) lit.value).intValue() == 0 ? false : true; } return lit.value; } else if (expr instanceof JCIdent || expr instanceof JCFieldAccess) { @@ -98,102 +147,176 @@ public class Javac { if (idx > -1) x = x.substring(idx + 1); } return x; - } else return null; - } - - public static final int CTC_BOOLEAN = getCtcInt(TypeTags.class, "BOOLEAN"); - public static final int CTC_INT = getCtcInt(TypeTags.class, "INT"); - public static final int CTC_DOUBLE = getCtcInt(TypeTags.class, "DOUBLE"); - public static final int CTC_FLOAT = getCtcInt(TypeTags.class, "FLOAT"); - public static final int CTC_SHORT = getCtcInt(TypeTags.class, "SHORT"); - public static final int CTC_BYTE = getCtcInt(TypeTags.class, "BYTE"); - public static final int CTC_LONG = getCtcInt(TypeTags.class, "LONG"); - public static final int CTC_CHAR = getCtcInt(TypeTags.class, "CHAR"); - public static final int CTC_VOID = getCtcInt(TypeTags.class, "VOID"); - public static final int CTC_NONE = getCtcInt(TypeTags.class, "NONE"); - - public static final int CTC_NOT_EQUAL = getCtcInt(JCTree.class, "NE"); - public static final int CTC_NOT = getCtcInt(JCTree.class, "NOT"); - public static final int CTC_BITXOR = getCtcInt(JCTree.class, "BITXOR"); - public static final int CTC_UNSIGNED_SHIFT_RIGHT = getCtcInt(JCTree.class, "USR"); - public static final int CTC_MUL = getCtcInt(JCTree.class, "MUL"); - public static final int CTC_PLUS = getCtcInt(JCTree.class, "PLUS"); - public static final int CTC_BOT = getCtcInt(TypeTags.class, "BOT"); - public static final int CTC_EQUAL = getCtcInt(JCTree.class, "EQ"); + } else + return null; + } - /** - * Retrieves a compile time constant of type int from the specified class location. - * - * Solves the problem of compile time constant inlining, resulting in lombok having the wrong value - * (javac compiler changes private api constants from time to time) - * - * @param ctcLocation location of the compile time constant - * @param identifier the name of the field of the compile time constant. - */ - public static int getCtcInt(Class<?> ctcLocation, String identifier) { + public static final TypeTag CTC_BOOLEAN = typeTag("BOOLEAN"); + public static final TypeTag CTC_INT = typeTag("INT"); + public static final TypeTag CTC_DOUBLE = typeTag("DOUBLE"); + public static final TypeTag CTC_FLOAT = typeTag("FLOAT"); + public static final TypeTag CTC_SHORT = typeTag("SHORT"); + public static final TypeTag CTC_BYTE = typeTag("BYTE"); + public static final TypeTag CTC_LONG = typeTag("LONG"); + public static final TypeTag CTC_CHAR = typeTag("CHAR"); + public static final TypeTag CTC_VOID = typeTag("VOID"); + public static final TypeTag CTC_NONE = typeTag("NONE"); + public static final TypeTag CTC_BOT = typeTag("BOT"); + public static final TypeTag CTC_CLASS = typeTag("CLASS"); + + public static final TreeTag CTC_NOT_EQUAL = treeTag("NE"); + public static final TreeTag CTC_POS = treeTag("POS"); + public static final TreeTag CTC_NEG = treeTag("NEG"); + public static final TreeTag CTC_NOT = treeTag("NOT"); + public static final TreeTag CTC_COMPL = treeTag("COMPL"); + public static final TreeTag CTC_BITXOR = treeTag("BITXOR"); + public static final TreeTag CTC_UNSIGNED_SHIFT_RIGHT = treeTag("USR"); + public static final TreeTag CTC_MUL = treeTag("MUL"); + public static final TreeTag CTC_PLUS = treeTag("PLUS"); + public static final TreeTag CTC_EQUAL = treeTag("EQ"); + public static final TreeTag CTC_PREINC = treeTag("PREINC"); + public static final TreeTag CTC_PREDEC = treeTag("PREDEC"); + + private static final Method getExtendsClause, getEndPosition; + + static { + getExtendsClause = getMethod(JCClassDecl.class, "getExtendsClause", new Class<?>[0]); + getExtendsClause.setAccessible(true); + + if (getJavaCompilerVersion() < 8) { + getEndPosition = getMethod(DiagnosticPosition.class, "getEndPosition", java.util.Map.class); + } else { + getEndPosition = getMethod(DiagnosticPosition.class, "getEndPosition", "com.sun.tools.javac.tree.EndPosTable"); + } + getEndPosition.setAccessible(true); + } + + private static Method getMethod(Class<?> clazz, String name, Class<?>... paramTypes) { try { - return (Integer)ctcLocation.getField(identifier).get(null); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); + return clazz.getMethod(name, paramTypes); + } catch (NoSuchMethodException e) { + throw sneakyThrow(e); } } - private static final Field JCTREE_TAG; - private static final Method JCTREE_GETTAG; - static { - Field f = null; + private static Method getMethod(Class<?> clazz, String name, String... paramTypes) { try { - f = JCTree.class.getDeclaredField("tag"); - } catch (NoSuchFieldException e) {} - JCTREE_TAG = f; - - Method m = null; + Class<?>[] c = new Class[paramTypes.length]; + for (int i = 0; i < paramTypes.length; i++) c[i] = Class.forName(paramTypes[i]); + return clazz.getMethod(name, c); + } catch (NoSuchMethodException e) { + throw sneakyThrow(e); + } catch (ClassNotFoundException e) { + throw sneakyThrow(e); + } + } + + public static JCTree getExtendsClause(JCClassDecl decl) { try { - m = JCTree.class.getDeclaredMethod("getTag"); - } catch (NoSuchMethodException e) {} - JCTREE_GETTAG = m; + return (JCTree) getExtendsClause.invoke(decl); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } catch (InvocationTargetException e) { + throw sneakyThrow(e.getCause()); + } } - public static int getTag(JCTree node) { - if (JCTREE_GETTAG != null) { - try { - return (Integer) JCTREE_GETTAG.invoke(node); - } catch (Exception e) {} + public static Object getDocComments(JCCompilationUnit cu) { + try { + return JCCOMPILATIONUNIT_DOCCOMMENTS.get(cu); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } + } + + public static void initDocComments(JCCompilationUnit cu) { + try { + JCCOMPILATIONUNIT_DOCCOMMENTS.set(cu, new HashMap<Object, String>()); + } catch (IllegalArgumentException e) { + // That's fine - we're on JDK8, we'll fix that later. + } catch (IllegalAccessException e) { + throw sneakyThrow(e); } + } + + public static int getEndPosition(DiagnosticPosition pos, JCCompilationUnit top) { try { - return (Integer) JCTREE_TAG.get(node); - } catch (Exception e) { - throw new IllegalStateException("Can't get node tag"); + Object endPositions = JCCOMPILATIONUNIT_ENDPOSITIONS.get(top); + return (Integer) getEndPosition.invoke(pos, endPositions); + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } catch (InvocationTargetException e) { + throw sneakyThrow(e.getCause()); } } - private static Method method; + private static final Class<?> JC_VOID_TYPE, JC_NO_TYPE; + + static { + Class<?> c = null; + try { + c = Class.forName("com.sun.tools.javac.code.Type$JCVoidType"); + } catch (Throwable ignore) {} + JC_VOID_TYPE = c; + c = null; + try { + c = Class.forName("com.sun.tools.javac.code.Type$JCNoType"); + } catch (Throwable ignore) {} + JC_NO_TYPE = c; + } - public static JCClassDecl ClassDef(TreeMaker maker, JCModifiers mods, Name name, List<JCTypeParameter> typarams, JCExpression extending, List<JCExpression> implementing, List<JCTree> defs) { - if (method == null) try { - method = TreeMaker.class.getDeclaredMethod("ClassDef", JCModifiers.class, Name.class, List.class, JCExpression.class, List.class, List.class); - } catch (NoSuchMethodException ignore) {} - if (method == null) try { - method = TreeMaker.class.getDeclaredMethod("ClassDef", JCModifiers.class, Name.class, List.class, JCTree.class, List.class, List.class); - } catch (NoSuchMethodException ignore) {} + public static Type createVoidType(JavacTreeMaker maker, TypeTag tag) { + if (Javac.getJavaCompilerVersion() < 8) { + return new JCNoType(((Integer) tag.value).intValue()); + } else { + try { + if (CTC_VOID.equals(tag)) { + return (Type) JC_VOID_TYPE.newInstance(); + } else { + return (Type) JC_NO_TYPE.newInstance(); + } + } catch (IllegalAccessException e) { + throw sneakyThrow(e); + } catch (InstantiationException e) { + throw sneakyThrow(e); + } + } + } + + private static class JCNoType extends Type implements NoType { + public JCNoType(int tag) { + super(tag, null); + } - if (method == null) throw new IllegalStateException("Lombok bug #20130617-1310: ClassDef doesn't look like anything we thought it would look like."); - if (!Modifier.isPublic(method.getModifiers()) && !method.isAccessible()) { - method.setAccessible(true); + @Override + public TypeKind getKind() { + if (tag == ((Integer) CTC_VOID.value).intValue()) return TypeKind.VOID; + if (tag == ((Integer) CTC_NONE.value).intValue()) return TypeKind.NONE; + throw new AssertionError("Unexpected tag: " + tag); } - try { - return (JCClassDecl) method.invoke(maker, mods, name, typarams, extending, implementing, defs); - } catch (InvocationTargetException e) { - throw sneakyThrow(e.getCause()); - } catch (IllegalAccessException e) { - throw sneakyThrow(e.getCause()); + @Override + public <R, P> R accept(TypeVisitor<R, P> v, P p) { + return v.visitNoType(this, p); } } - private static RuntimeException sneakyThrow(Throwable t) { + private static final Field JCCOMPILATIONUNIT_ENDPOSITIONS, JCCOMPILATIONUNIT_DOCCOMMENTS; + static { + Field f = null; + try { + f = JCCompilationUnit.class.getDeclaredField("endPositions"); + } catch (NoSuchFieldException e) {} + JCCOMPILATIONUNIT_ENDPOSITIONS = f; + + f = null; + try { + f = JCCompilationUnit.class.getDeclaredField("docComments"); + } catch (NoSuchFieldException e) {} + JCCOMPILATIONUNIT_DOCCOMMENTS = f; + } + + static RuntimeException sneakyThrow(Throwable t) { if (t == null) throw new NullPointerException("t"); Javac.<RuntimeException>sneakyThrow0(t); return null; diff --git a/src/utils/lombok/javac/JavacTreeMaker.java b/src/utils/lombok/javac/JavacTreeMaker.java new file mode 100644 index 00000000..12baf5af --- /dev/null +++ b/src/utils/lombok/javac/JavacTreeMaker.java @@ -0,0 +1,830 @@ +/* + * Copyright (C) 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; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import com.sun.tools.javac.code.Attribute; +import com.sun.tools.javac.code.BoundKind; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCArrayAccess; +import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; +import com.sun.tools.javac.tree.JCTree.JCAssert; +import com.sun.tools.javac.tree.JCTree.JCAssign; +import com.sun.tools.javac.tree.JCTree.JCAssignOp; +import com.sun.tools.javac.tree.JCTree.JCBinary; +import com.sun.tools.javac.tree.JCTree.JCBlock; +import com.sun.tools.javac.tree.JCTree.JCBreak; +import com.sun.tools.javac.tree.JCTree.JCCase; +import com.sun.tools.javac.tree.JCTree.JCCatch; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCConditional; +import com.sun.tools.javac.tree.JCTree.JCContinue; +import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop; +import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; +import com.sun.tools.javac.tree.JCTree.JCErroneous; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCExpressionStatement; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import com.sun.tools.javac.tree.JCTree.JCForLoop; +import com.sun.tools.javac.tree.JCTree.JCIdent; +import com.sun.tools.javac.tree.JCTree.JCIf; +import com.sun.tools.javac.tree.JCTree.JCImport; +import com.sun.tools.javac.tree.JCTree.JCInstanceOf; +import com.sun.tools.javac.tree.JCTree.JCLabeledStatement; +import com.sun.tools.javac.tree.JCTree.JCLiteral; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.JCModifiers; +import com.sun.tools.javac.tree.JCTree.JCNewArray; +import com.sun.tools.javac.tree.JCTree.JCNewClass; +import com.sun.tools.javac.tree.JCTree.JCParens; +import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree; +import com.sun.tools.javac.tree.JCTree.JCReturn; +import com.sun.tools.javac.tree.JCTree.JCSkip; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCSwitch; +import com.sun.tools.javac.tree.JCTree.JCSynchronized; +import com.sun.tools.javac.tree.JCTree.JCThrow; +import com.sun.tools.javac.tree.JCTree.JCTry; +import com.sun.tools.javac.tree.JCTree.JCTypeApply; +import com.sun.tools.javac.tree.JCTree.JCTypeCast; +import com.sun.tools.javac.tree.JCTree.JCTypeParameter; +import com.sun.tools.javac.tree.JCTree.JCUnary; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.JCTree.JCWhileLoop; +import com.sun.tools.javac.tree.JCTree.JCWildcard; +import com.sun.tools.javac.tree.JCTree.LetExpr; +import com.sun.tools.javac.tree.JCTree.TypeBoundKind; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.Name; + +public class JavacTreeMaker { + private final TreeMaker tm; + + public JavacTreeMaker(TreeMaker tm) { + this.tm = tm; + } + + public TreeMaker getUnderlyingTreeMaker() { + return tm; + } + + public JavacTreeMaker at(int pos) { + tm.at(pos); + return this; + } + + private static class MethodId<J> { + private final Class<?> owner; + private final String name; + private final Class<J> returnType; + private final Class<?>[] paramTypes; + + MethodId(Class<?> owner, String name, Class<J> returnType, Class<?>... types) { + this.owner = owner; + this.name = name; + this.paramTypes = types; + this.returnType = returnType; + } + + @Override public String toString() { + StringBuilder out = new StringBuilder(); + out.append(returnType.getName()).append(" ").append(owner.getName()).append(".").append(name).append("("); + boolean f = true; + for (Class<?> p : paramTypes) { + if (f) f = false; + else out.append(", "); + out.append(p.getName()); + } + return out.append(")").toString(); + } + } + + private static class SchroedingerType { + final Object value; + + private SchroedingerType(Object value) { + this.value = value; + } + + @Override public int hashCode() { + return value == null ? -1 : value.hashCode(); + } + + @Override public boolean equals(Object obj) { + if (obj instanceof SchroedingerType) { + Object other = ((SchroedingerType) obj).value; + return value == null ? other == null : value.equals(other); + } + return false; + } + + static Object getFieldCached(ConcurrentMap<String, Object> cache, String className, String fieldName) { + Object value = cache.get(fieldName); + if (value != null) return value; + try { + value = Class.forName(className).getField(fieldName).get(null); + } catch (NoSuchFieldException e) { + throw Javac.sneakyThrow(e); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } catch (ClassNotFoundException e) { + throw Javac.sneakyThrow(e); + } + + cache.putIfAbsent(fieldName, value); + return value; + } + + private static Field NOSUCHFIELDEX_MARKER; + static { + try { + NOSUCHFIELDEX_MARKER = SchroedingerType.class.getDeclaredField("NOSUCHFIELDEX_MARKER"); + } catch (NoSuchFieldException e) { + throw Javac.sneakyThrow(e); + } + } + + static Object getFieldCached(ConcurrentMap<Class<?>, Field> cache, Object ref, String fieldName) throws NoSuchFieldException { + Class<?> c = ref.getClass(); + Field field = cache.get(c); + if (field == null) { + try { + field = c.getField(fieldName); + } catch (NoSuchFieldException e) { + cache.putIfAbsent(c, NOSUCHFIELDEX_MARKER); + throw Javac.sneakyThrow(e); + } + field.setAccessible(true); + Field old = cache.putIfAbsent(c, field); + if (old != null) field = old; + } + + if (field == NOSUCHFIELDEX_MARKER) throw new NoSuchFieldException(fieldName); + try { + return field.get(ref); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } + } + } + + public static class TypeTag extends SchroedingerType { + private static final ConcurrentMap<String, Object> TYPE_TAG_CACHE = new ConcurrentHashMap<String, Object>(); + private static final ConcurrentMap<Class<?>, Field> FIELD_CACHE = new ConcurrentHashMap<Class<?>, Field>(); + private static final Method TYPE_TYPETAG_METHOD; + + static { + Method m = null; + try { + m = Type.class.getDeclaredMethod("getTag"); + m.setAccessible(true); + } catch (NoSuchMethodException e) {} + TYPE_TYPETAG_METHOD = m; + } + + private TypeTag(Object value) { + super(value); + } + + public static TypeTag typeTag(JCTree o) { + try { + return new TypeTag(getFieldCached(FIELD_CACHE, o, "typetag")); + } catch (NoSuchFieldException e) { + throw Javac.sneakyThrow(e); + } + } + + public static TypeTag typeTag(Type t) { + try { + return new TypeTag(getFieldCached(FIELD_CACHE, t, "tag")); + } catch (NoSuchFieldException e) { + if (TYPE_TYPETAG_METHOD == null) throw new IllegalStateException("Type " + t.getClass() + " has neither 'tag' nor getTag()"); + try { + return new TypeTag(TYPE_TYPETAG_METHOD.invoke(t)); + } catch (IllegalAccessException ex) { + throw Javac.sneakyThrow(ex); + } catch (InvocationTargetException ex) { + throw Javac.sneakyThrow(ex.getCause()); + } + } + } + + public static TypeTag typeTag(String identifier) { + return new TypeTag(getFieldCached(TYPE_TAG_CACHE, Javac.getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.code.TypeTags" : "com.sun.tools.javac.code.TypeTag", identifier)); + } + } + + public static class TreeTag extends SchroedingerType { + private static final ConcurrentMap<String, Object> TREE_TAG_CACHE = new ConcurrentHashMap<String, Object>(); + private static final Field TAG_FIELD; + private static final Method TAG_METHOD; + private static final MethodId<Integer> OP_PREC = MethodId(TreeInfo.class, "opPrec", int.class, TreeTag.class); + + static { + Method m = null; + try { + m = JCTree.class.getDeclaredMethod("getTag"); + m.setAccessible(true); + } catch (NoSuchMethodException e) {} + + if (m != null) { + TAG_FIELD = null; + TAG_METHOD = m; + } else { + Field f = null; + try { + f = JCTree.class.getDeclaredField("tag"); + f.setAccessible(true); + } catch (NoSuchFieldException e) {} + TAG_FIELD = f; + TAG_METHOD = null; + } + } + + private TreeTag(Object value) { + super(value); + } + + public static TreeTag treeTag(JCTree o) { + try { + if (TAG_METHOD != null) return new TreeTag(TAG_METHOD.invoke(o)); + else return new TreeTag(TAG_FIELD.get(o)); + } catch (InvocationTargetException e) { + throw Javac.sneakyThrow(e.getCause()); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } + } + + public static TreeTag treeTag(String identifier) { + return new TreeTag(getFieldCached(TREE_TAG_CACHE, Javac.getJavaCompilerVersion() < 8 ? "com.sun.tools.javac.tree.JCTree" : "com.sun.tools.javac.tree.JCTree$Tag", identifier)); + } + + public int getOperatorPrecedenceLevel() { + return invokeAny(null, OP_PREC, value); + } + + public boolean isPrefixUnaryOp() { + return Javac.CTC_NEG.equals(this) || Javac.CTC_POS.equals(this) || Javac.CTC_NOT.equals(this) || Javac.CTC_COMPL.equals(this) || Javac.CTC_PREDEC.equals(this) || Javac.CTC_PREINC.equals(this); + } + } + + static <J> MethodId<J> MethodId(Class<?> owner, String name, Class<J> returnType, Class<?>... types) { + return new MethodId<J>(owner, name, returnType, types); + } + + /** + * Creates a new method ID based on the name of the method to invoke, the return type of that method, and the types of the parameters. + * + * A method matches if the return type matches, and for each parameter the following holds: + * + * Either (A) the type listed here is the same as, or a subtype of, the type of the method in javac's TreeMaker, or + * (B) the type listed here is a subtype of SchroedingerType. + */ + static <J> MethodId<J> MethodId(String name, Class<J> returnType, Class<?>... types) { + return new MethodId<J>(TreeMaker.class, name, returnType, types); + } + + /** + * Creates a new method ID based on the name of a method in this class, assuming the name of the method to invoke in TreeMaker has the same name, + * the same return type, and the same parameters (under the same rules as the other MethodId method). + */ + static <J> MethodId<J> MethodId(String name) { + for (Method m : JavacTreeMaker.class.getDeclaredMethods()) { + if (m.getName().equals(name)) { + @SuppressWarnings("unchecked") Class<J> r = (Class<J>) m.getReturnType(); + Class<?>[] p = m.getParameterTypes(); + return new MethodId<J>(TreeMaker.class, name, r, p); + } + } + + throw new InternalError("Not found: " + name); + } + + private static final ConcurrentHashMap<MethodId<?>, Method> METHOD_CACHE = new ConcurrentHashMap<MethodId<?>, Method>(); + private <J> J invoke(MethodId<J> m, Object... args) { + return invokeAny(tm, m, args); + } + + @SuppressWarnings("unchecked") private static <J> J invokeAny(Object owner, MethodId<J> m, Object... args) { + Method method = METHOD_CACHE.get(m); + if (method == null) method = addToCache(m); + try { + if (m.returnType.isPrimitive()) { + Object res = method.invoke(owner, args); + String sn = res.getClass().getSimpleName().toLowerCase(); + if (!sn.startsWith(m.returnType.getSimpleName())) throw new ClassCastException(res.getClass() + " to " + m.returnType); + return (J) res; + } + return m.returnType.cast(method.invoke(owner, args)); + } catch (InvocationTargetException e) { + throw Javac.sneakyThrow(e.getCause()); + } catch (IllegalAccessException e) { + throw Javac.sneakyThrow(e); + } catch (IllegalArgumentException e) { + System.err.println(method); + throw Javac.sneakyThrow(e); + } + } + + private static Method addToCache(MethodId<?> m) { + Method found = null; + + outer: + for (Method method : m.owner.getDeclaredMethods()) { + if (!m.name.equals(method.getName())) continue; + Class<?>[] t = method.getParameterTypes(); + if (t.length != m.paramTypes.length) continue; + for (int i = 0; i < t.length; i++) { + if (Symbol.class.isAssignableFrom(t[i])) continue outer; + if (!SchroedingerType.class.isAssignableFrom(m.paramTypes[i])) { + if (t[i].isPrimitive()) { + if (t[i] != m.paramTypes[i]) continue outer; + } else { + if (!t[i].isAssignableFrom(m.paramTypes[i])) continue outer; + } + } + } + if (found == null) found = method; + else throw new IllegalStateException("Lombok TreeMaker frontend issue: multiple matches when looking for method: " + m); + } + if (found == null) throw new IllegalStateException("Lombok TreeMaker frontend issue: no match when looking for method: " + m); + found.setAccessible(true); + Object marker = METHOD_CACHE.putIfAbsent(m, found); + if (marker == null) return found; + return METHOD_CACHE.get(m); + } + + //javac versions: 6-8 + private static final MethodId<JCCompilationUnit> TopLevel = MethodId("TopLevel"); + public JCCompilationUnit TopLevel(List<JCAnnotation> packageAnnotations, JCExpression pid, List<JCTree> defs) { + return invoke(TopLevel, packageAnnotations, pid, defs); + } + + //javac versions: 6-8 + private static final MethodId<JCImport> Import = MethodId("Import"); + public JCImport Import(JCTree qualid, boolean staticImport) { + return invoke(Import, qualid, staticImport); + } + + //javac versions: 6-8 + private static final MethodId<JCClassDecl> ClassDef = MethodId("ClassDef"); + public JCClassDecl ClassDef(JCModifiers mods, Name name, List<JCTypeParameter> typarams, JCExpression extending, List<JCExpression> implementing, List<JCTree> defs) { + return invoke(ClassDef, mods, name, typarams, extending, implementing, defs); + } + + //javac versions: 6-8 + private static final MethodId<JCMethodDecl> MethodDef = MethodId("MethodDef", JCMethodDecl.class, JCModifiers.class, Name.class, JCExpression.class, List.class, List.class, List.class, JCBlock.class, JCExpression.class); + public JCMethodDecl MethodDef(JCModifiers mods, Name name, JCExpression resType, List<JCTypeParameter> typarams, List<JCVariableDecl> params, List<JCExpression> thrown, JCBlock body, JCExpression defaultValue) { + return invoke(MethodDef, mods, name, resType, typarams, params, thrown, body, defaultValue); + } + + //javac versions: 8 + private static final MethodId<JCMethodDecl> MethodDefWithRecvParam = MethodId("MethodDef", JCMethodDecl.class, JCModifiers.class, Name.class, JCExpression.class, List.class, JCVariableDecl.class, List.class, List.class, JCBlock.class, JCExpression.class); + public JCMethodDecl MethodDef(JCModifiers mods, Name name, JCExpression resType, List<JCTypeParameter> typarams, JCVariableDecl recvparam, List<JCVariableDecl> params, List<JCExpression> thrown, JCBlock body, JCExpression defaultValue) { + return invoke(MethodDefWithRecvParam, mods, name, resType, recvparam, typarams, params, thrown, body, defaultValue); + } + + //javac versions: 6-8 + private static final MethodId<JCVariableDecl> VarDef = MethodId("VarDef"); + public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init) { + return invoke(VarDef, mods, name, vartype, init); + } + + //javac versions: 8 + private static final MethodId<JCVariableDecl> ReceiverVarDef = MethodId("ReceiverVarDef"); + public JCVariableDecl ReceiverVarDef(JCModifiers mods, JCExpression name, JCExpression vartype) { + return invoke(ReceiverVarDef, mods, name, vartype); + } + + //javac versions: 6-8 + private static final MethodId<JCSkip> Skip = MethodId("Skip"); + public JCSkip Skip() { + return invoke(Skip); + } + + //javac versions: 6-8 + private static final MethodId<JCBlock> Block = MethodId("Block"); + public JCBlock Block(long flags, List<JCStatement> stats) { + return invoke(Block, flags, stats); + } + + //javac versions: 6-8 + private static final MethodId<JCDoWhileLoop> DoLoop = MethodId("DoLoop"); + public JCDoWhileLoop DoLoop(JCStatement body, JCExpression cond) { + return invoke(DoLoop, body, cond); + } + + //javac versions: 6-8 + private static final MethodId<JCWhileLoop> WhileLoop = MethodId("WhileLoop"); + public JCWhileLoop WhileLoop(JCExpression cond, JCStatement body) { + return invoke(WhileLoop, cond, body); + } + + //javac versions: 6-8 + private static final MethodId<JCForLoop> ForLoop = MethodId("ForLoop"); + public JCForLoop ForLoop(List<JCStatement> init, JCExpression cond, List<JCExpressionStatement> step, JCStatement body) { + return invoke(ForLoop, init, cond, step, body); + } + + //javac versions: 6-8 + private static final MethodId<JCEnhancedForLoop> ForeachLoop = MethodId("ForeachLoop"); + public JCEnhancedForLoop ForeachLoop(JCVariableDecl var, JCExpression expr, JCStatement body) { + return invoke(ForeachLoop, var, expr, body); + } + + //javac versions: 6-8 + private static final MethodId<JCLabeledStatement> Labelled = MethodId("Labelled"); + public JCLabeledStatement Labelled(Name label, JCStatement body) { + return invoke(Labelled, label, body); + } + + //javac versions: 6-8 + private static final MethodId<JCSwitch> Switch = MethodId("Switch"); + public JCSwitch Switch(JCExpression selector, List<JCCase> cases) { + return invoke(Switch, selector, cases); + } + + //javac versions: 6-8 + private static final MethodId<JCCase> Case = MethodId("Case"); + public JCCase Case(JCExpression pat, List<JCStatement> stats) { + return invoke(Case, pat, stats); + } + + //javac versions: 6-8 + private static final MethodId<JCSynchronized> Synchronized = MethodId("Synchronized"); + public JCSynchronized Synchronized(JCExpression lock, JCBlock body) { + return invoke(Synchronized, lock, body); + } + + //javac versions: 6-8 + private static final MethodId<JCTry> Try = MethodId("Try", JCTry.class, JCBlock.class, List.class, JCBlock.class); + public JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer) { + return invoke(Try, body, catchers, finalizer); + } + + //javac versions: 7-8 + private static final MethodId<JCTry> TryWithResources = MethodId("Try", JCTry.class, List.class, JCBlock.class, List.class, JCBlock.class); + public JCTry Try(List<JCTree> resources, JCBlock body, List<JCCatch> catchers, JCBlock finalizer) { + return invoke(TryWithResources, resources, body, catchers, finalizer); + } + + //javac versions: 6-8 + private static final MethodId<JCCatch> Catch = MethodId("Catch"); + public JCCatch Catch(JCVariableDecl param, JCBlock body) { + return invoke(Catch, param, body); + } + + //javac versions: 6-8 + private static final MethodId<JCConditional> Conditional = MethodId("Conditional"); + public JCConditional Conditional(JCExpression cond, JCExpression thenpart, JCExpression elsepart) { + return invoke(Conditional, cond, thenpart, elsepart); + } + + //javac versions: 6-8 + private static final MethodId<JCIf> If = MethodId("If"); + public JCIf If(JCExpression cond, JCStatement thenpart, JCStatement elsepart) { + return invoke(If, cond, thenpart, elsepart); + } + + //javac versions: 6-8 + private static final MethodId<JCExpressionStatement> Exec = MethodId("Exec"); + public JCExpressionStatement Exec(JCExpression expr) { + return invoke(Exec, expr); + } + + //javac versions: 6-8 + private static final MethodId<JCBreak> Break = MethodId("Break"); + public JCBreak Break(Name label) { + return invoke(Break, label); + } + + //javac versions: 6-8 + private static final MethodId<JCContinue> Continue = MethodId("Continue"); + public JCContinue Continue(Name label) { + return invoke(Continue, label); + } + + //javac versions: 6-8 + private static final MethodId<JCReturn> Return = MethodId("Return"); + public JCReturn Return(JCExpression expr) { + return invoke(Return, expr); + } + + //javac versions: 6-8 + private static final MethodId<JCThrow> Throw = MethodId("Throw"); + public JCThrow Throw(JCExpression expr) { + return invoke(Throw, expr); + } + + //javac versions: 6-8 + private static final MethodId<JCAssert> Assert = MethodId("Assert"); + public JCAssert Assert(JCExpression cond, JCExpression detail) { + return invoke(Assert, cond, detail); + } + + //javac versions: 6-8 + private static final MethodId<JCMethodInvocation> Apply = MethodId("Apply"); + public JCMethodInvocation Apply(List<JCExpression> typeargs, JCExpression fn, List<JCExpression> args) { + return invoke(Apply, typeargs, fn, args); + } + + //javac versions: 6-8 + private static final MethodId<JCNewClass> NewClass = MethodId("NewClass"); + public JCNewClass NewClass(JCExpression encl, List<JCExpression> typeargs, JCExpression clazz, List<JCExpression> args, JCClassDecl def) { + return invoke(NewClass, encl, typeargs, clazz, args, def); + } + + //javac versions: 6-8 + private static final MethodId<JCNewArray> NewArray = MethodId("NewArray"); + public JCNewArray NewArray(JCExpression elemtype, List<JCExpression> dims, List<JCExpression> elems) { + return invoke(NewArray, elemtype, dims, elems); + } + + //javac versions: 8 +// private static final MethodId<JCLambda> Lambda = MethodId("Lambda"); +// public JCLambda Lambda(List<JCVariableDecl> params, JCTree body) { +// return invoke(Lambda, params, body); +// } + + //javac versions: 6-8 + private static final MethodId<JCParens> Parens = MethodId("Parens"); + public JCParens Parens(JCExpression expr) { + return invoke(Parens, expr); + } + + //javac versions: 6-8 + private static final MethodId<JCAssign> Assign = MethodId("Assign"); + public JCAssign Assign(JCExpression lhs, JCExpression rhs) { + return invoke(Assign, lhs, rhs); + } + + //javac versions: 6-8 + //opcode = [6-7] int [8] JCTree.Tag + private static final MethodId<JCAssignOp> Assignop = MethodId("Assignop"); + public JCAssignOp Assignop(TreeTag opcode, JCTree lhs, JCTree rhs) { + return invoke(Assignop, opcode.value, lhs, rhs); + } + + //javac versions: 6-8 + //opcode = [6-7] int [8] JCTree.Tag + private static final MethodId<JCUnary> Unary = MethodId("Unary"); + public JCUnary Unary(TreeTag opcode, JCExpression arg) { + return invoke(Unary, opcode.value, arg); + } + + //javac versions: 6-8 + //opcode = [6-7] int [8] JCTree.Tag + private static final MethodId<JCBinary> Binary = MethodId("Binary"); + public JCBinary Binary(TreeTag opcode, JCExpression lhs, JCExpression rhs) { + return invoke(Binary, opcode.value, lhs, rhs); + } + + //javac versions: 6-8 + private static final MethodId<JCTypeCast> TypeCast = MethodId("TypeCast"); + public JCTypeCast TypeCast(JCTree expr, JCExpression type) { + return invoke(TypeCast, expr, type); + } + + //javac versions: 6-8 + private static final MethodId<JCInstanceOf> TypeTest = MethodId("TypeTest"); + public JCInstanceOf TypeTest(JCExpression expr, JCTree clazz) { + return invoke(TypeTest, expr, clazz); + } + + //javac versions: 6-8 + private static final MethodId<JCArrayAccess> Indexed = MethodId("Indexed"); + public JCArrayAccess Indexed(JCExpression indexed, JCExpression index) { + return invoke(Indexed, indexed, index); + } + + //javac versions: 6-8 + private static final MethodId<JCFieldAccess> Select = MethodId("Select"); + public JCFieldAccess Select(JCExpression selected, Name selector) { + return invoke(Select, selected, selector); + } + + //javac versions: 8 +// private static final MethodId<JCMemberReference> Reference = MethodId("Reference"); +// public JCMemberReference Reference(JCMemberReference.ReferenceMode mode, Name name, JCExpression expr, List<JCExpression> typeargs) { +// return invoke(Reference, mode, name, expr, typeargs); +// } + + //javac versions: 6-8 + private static final MethodId<JCIdent> Ident = MethodId("Ident", JCIdent.class, Name.class); + public JCIdent Ident(Name idname) { + return invoke(Ident, idname); + } + + //javac versions: 6-8 + //tag = [6-7] int [8] TypeTag + private static final MethodId<JCLiteral> Literal = MethodId("Literal", JCLiteral.class, TypeTag.class, Object.class); + public JCLiteral Literal(TypeTag tag, Object value) { + return invoke(Literal, tag.value, value); + } + + //javac versions: 6-8 + //typetag = [6-7] int [8] TypeTag + private static final MethodId<JCPrimitiveTypeTree> TypeIdent = MethodId("TypeIdent"); + public JCPrimitiveTypeTree TypeIdent(TypeTag typetag) { + return invoke(TypeIdent, typetag.value); + } + //javac versions: 6-8 + private static final MethodId<JCArrayTypeTree> TypeArray = MethodId("TypeArray"); + public JCArrayTypeTree TypeArray(JCExpression elemtype) { + return invoke(TypeArray, elemtype); + } + + //javac versions: 6-8 + private static final MethodId<JCTypeApply> TypeApply = MethodId("TypeApply"); + public JCTypeApply TypeApply(JCExpression clazz, List<JCExpression> arguments) { + return invoke(TypeApply, clazz, arguments); + } + + //javac versions: 7-8 +// private static final MethodId<JCTypeUnion> TypeUnion = MethodId("TypeUnion"); +// public JCTypeUnion TypeUnion(List<JCExpression> components) { +// return invoke(TypeUnion, compoonents); +// } + + //javac versions: 8 +// private static final MethodId<JCTypeIntersection> TypeIntersection = MethodId("TypeIntersection"); +// public JCTypeIntersection TypeIntersection(List<JCExpression> components) { +// return invoke(TypeIntersection, components); +// } + + //javac versions: 6-8 + private static final MethodId<JCTypeParameter> TypeParameter = MethodId("TypeParameter", JCTypeParameter.class, Name.class, List.class); + public JCTypeParameter TypeParameter(Name name, List<JCExpression> bounds) { + return invoke(TypeParameter, name, bounds); + } + + //javac versions: 8 + private static final MethodId<JCTypeParameter> TypeParameterWithAnnos = MethodId("TypeParameter", JCTypeParameter.class, Name.class, List.class, List.class); + public JCTypeParameter TypeParameter(Name name, List<JCExpression> bounds, List<JCAnnotation> annos) { + return invoke(TypeParameterWithAnnos, name, bounds, annos); + } + + //javac versions: 6-8 + private static final MethodId<JCWildcard> Wildcard = MethodId("Wildcard"); + public JCWildcard Wildcard(TypeBoundKind kind, JCTree type) { + return invoke(Wildcard, kind, type); + } + + //javac versions: 6-8 + private static final MethodId<TypeBoundKind> TypeBoundKind = MethodId("TypeBoundKind"); + public TypeBoundKind TypeBoundKind(BoundKind kind) { + return invoke(TypeBoundKind, kind); + } + + //javac versions: 6-8 + private static final MethodId<JCAnnotation> Annotation = MethodId("Annotation", JCAnnotation.class, JCTree.class, List.class); + public JCAnnotation Annotation(JCTree annotationType, List<JCExpression> args) { + return invoke(Annotation, annotationType, args); + } + + //javac versions: 8 + private static final MethodId<JCAnnotation> TypeAnnotation = MethodId("TypeAnnotation", JCAnnotation.class, JCTree.class, List.class); + public JCAnnotation TypeAnnotation(JCTree annotationType, List<JCExpression> args) { + return invoke(TypeAnnotation, annotationType, args); + } + + //javac versions: 6-8 + private static final MethodId<JCModifiers> ModifiersWithAnnotations = MethodId("Modifiers", JCModifiers.class, long.class, List.class); + public JCModifiers Modifiers(long flags, List<JCAnnotation> annotations) { + return invoke(ModifiersWithAnnotations, flags, annotations); + } + + //javac versions: 6-8 + private static final MethodId<JCModifiers> Modifiers = MethodId("Modifiers", JCModifiers.class, long.class); + public JCModifiers Modifiers(long flags) { + return invoke(Modifiers, flags); + } + + //javac versions: 8 +// private static final MethodId<JCAnnotatedType> AnnotatedType = MethodId("AnnotatedType"); +// public JCAnnotatedType AnnotatedType(List<JCAnnotation> annotations, JCExpression underlyingType) { +// return invoke(AnnotatedType, annotations, underlyingType); +// } + + //javac versions: 6-8 + private static final MethodId<JCErroneous> Erroneous = MethodId("Erroneous", JCErroneous.class); + public JCErroneous Erroneous() { + return invoke(Erroneous); + } + + //javac versions: 6-8 + private static final MethodId<JCErroneous> ErroneousWithErrs = MethodId("Erroneous", JCErroneous.class, List.class); + public JCErroneous Erroneous(List<? extends JCTree> errs) { + return invoke(ErroneousWithErrs, errs); + } + + //javac versions: 6-8 + private static final MethodId<LetExpr> LetExpr = MethodId("LetExpr", LetExpr.class, List.class, JCTree.class); + public LetExpr LetExpr(List<JCVariableDecl> defs, JCTree expr) { + return invoke(LetExpr, defs, expr); + } + + //javac versions: 6-8 + private static final MethodId<JCClassDecl> AnonymousClassDef = MethodId("AnonymousClassDef"); + public JCClassDecl AnonymousClassDef(JCModifiers mods, List<JCTree> defs) { + return invoke(AnonymousClassDef, mods, defs); + } + + //javac versions: 6-8 + private static final MethodId<LetExpr> LetExprSingle = MethodId("LetExpr", LetExpr.class, JCVariableDecl.class, JCTree.class); + public LetExpr LetExpr(JCVariableDecl def, JCTree expr) { + return invoke(LetExprSingle, def, expr); + } + + //javac versions: 6-8 + private static final MethodId<JCIdent> IdentVarDecl = MethodId("Ident", JCIdent.class, JCVariableDecl.class); + public JCExpression Ident(JCVariableDecl param) { + return invoke(IdentVarDecl, param); + } + + //javac versions: 6-8 + private static final MethodId<List<JCExpression>> Idents = MethodId("Idents"); + public List<JCExpression> Idents(List<JCVariableDecl> params) { + return invoke(Idents, params); + } + + //javac versions: 6-8 + private static final MethodId<JCMethodInvocation> App2 = MethodId("App", JCMethodInvocation.class, JCExpression.class, List.class); + public JCMethodInvocation App(JCExpression meth, List<JCExpression> args) { + return invoke(App2, meth, args); + } + + //javac versions: 6-8 + private static final MethodId<JCMethodInvocation> App1 = MethodId("App", JCMethodInvocation.class, JCExpression.class); + public JCMethodInvocation App(JCExpression meth) { + return invoke(App1, meth); + } + + //javac versions: 6-8 + private static final MethodId<List<JCAnnotation>> Annotations = MethodId("Annotations"); + public List<JCAnnotation> Annotations(List<Attribute.Compound> attributes) { + return invoke(Annotations, attributes); + } + + //javac versions: 6-8 + private static final MethodId<JCLiteral> LiteralWithValue = MethodId("Literal", JCLiteral.class, Object.class); + public JCLiteral Literal(Object value) { + return invoke(LiteralWithValue, value); + } + + //javac versions: 6-8 + private static final MethodId<JCAnnotation> AnnotationWithAttributeOnly = MethodId("Annotation", JCAnnotation.class, Attribute.class); + public JCAnnotation Annotation(Attribute a) { + return invoke(AnnotationWithAttributeOnly, a); + } + + //javac versions: 8 + private static final MethodId<JCAnnotation> TypeAnnotationWithAttributeOnly = MethodId("TypeAnnotation", JCAnnotation.class, Attribute.class); + public JCAnnotation TypeAnnotation(Attribute a) { + return invoke(TypeAnnotationWithAttributeOnly, a); + } + + //javac versions: 6-8 + private static final MethodId<JCStatement> Call = MethodId("Call"); + public JCStatement Call(JCExpression apply) { + return invoke(Call, apply); + } + + //javac versions: 6-8 + private static final MethodId<JCExpression> Type = MethodId("Type"); + public JCExpression Type(Type type) { + return invoke(Type, type); + } +}
\ No newline at end of file diff --git a/src/utils/lombok/javac/TreeMirrorMaker.java b/src/utils/lombok/javac/TreeMirrorMaker.java index 30915572..23ec2406 100644 --- a/src/utils/lombok/javac/TreeMirrorMaker.java +++ b/src/utils/lombok/javac/TreeMirrorMaker.java @@ -31,7 +31,6 @@ import com.sun.source.tree.VariableTree; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.TreeCopier; -import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.List; /** @@ -47,8 +46,8 @@ import com.sun.tools.javac.util.List; public class TreeMirrorMaker extends TreeCopier<Void> { private final IdentityHashMap<JCTree, JCTree> originalToCopy = new IdentityHashMap<JCTree, JCTree>(); - public TreeMirrorMaker(TreeMaker maker) { - super(maker); + public TreeMirrorMaker(JavacTreeMaker maker) { + super(maker.getUnderlyingTreeMaker()); } @Override public <T extends JCTree> T copy(T original) { diff --git a/src/utils/lombok/javac/java6/CommentCollectingParser.java b/src/utils/lombok/javac/java6/CommentCollectingParser.java index 94a85e55..30192b06 100644 --- a/src/utils/lombok/javac/java6/CommentCollectingParser.java +++ b/src/utils/lombok/javac/java6/CommentCollectingParser.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 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.java6; import java.util.Map; diff --git a/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java b/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java index 7e34b723..b250b898 100644 --- a/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java +++ b/src/utils/lombok/javac/java6/CommentCollectingParserFactory.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 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.java6; import java.lang.reflect.Field; diff --git a/src/utils/lombok/javac/java6/CommentCollectingScanner.java b/src/utils/lombok/javac/java6/CommentCollectingScanner.java index b584ec16..df383b93 100644 --- a/src/utils/lombok/javac/java6/CommentCollectingScanner.java +++ b/src/utils/lombok/javac/java6/CommentCollectingScanner.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Project Lombok Authors. + * 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 @@ -27,11 +27,12 @@ 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 { - private final ListBuffer<CommentInfo> comments = ListBuffer.lb(); +public class CommentCollectingScanner extends Scanner { + private final ListBuffer<CommentInfo> comments = new ListBuffer<CommentInfo>(); private int endComment = 0; public CommentCollectingScanner(CommentCollectingScannerFactory factory, CharBuffer charBuffer) { diff --git a/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java b/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java index f3d6bd72..b7d8ed13 100644 --- a/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java +++ b/src/utils/lombok/javac/java6/CommentCollectingScannerFactory.java @@ -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) { diff --git a/src/utils/lombok/javac/java6/DocCommentScanner.java b/src/utils/lombok/javac/java6/DocCommentScanner.java deleted file mode 100644 index ff3eadd4..00000000 --- a/src/utils/lombok/javac/java6/DocCommentScanner.java +++ /dev/null @@ -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); - } -} diff --git a/src/utils/lombok/javac/java7/CommentCollectingParser.java b/src/utils/lombok/javac/java7/CommentCollectingParser.java index 82f19c42..0e8a4ef6 100644 --- a/src/utils/lombok/javac/java7/CommentCollectingParser.java +++ b/src/utils/lombok/javac/java7/CommentCollectingParser.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 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.java7; import java.util.List; diff --git a/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java b/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java index e9575c14..ed8279df 100644 --- a/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java +++ b/src/utils/lombok/javac/java7/CommentCollectingParserFactory.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 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.java7; import java.lang.reflect.Field; diff --git a/src/utils/lombok/javac/java7/CommentCollectingScanner.java b/src/utils/lombok/javac/java7/CommentCollectingScanner.java index 6ebd3ac1..3f76f910 100644 --- a/src/utils/lombok/javac/java7/CommentCollectingScanner.java +++ b/src/utils/lombok/javac/java7/CommentCollectingScanner.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Project Lombok Authors. + * 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 @@ -27,12 +27,12 @@ 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 { - private final ListBuffer<CommentInfo> comments = ListBuffer.lb(); +public class CommentCollectingScanner extends Scanner { + private final ListBuffer<CommentInfo> comments = new ListBuffer<CommentInfo>(); private int endComment = 0; public CommentCollectingScanner(CommentCollectingScannerFactory factory, CharBuffer charBuffer) { diff --git a/src/utils/lombok/javac/java8/CommentCollectingParser.java b/src/utils/lombok/javac/java8/CommentCollectingParser.java new file mode 100644 index 00000000..e305e44f --- /dev/null +++ b/src/utils/lombok/javac/java8/CommentCollectingParser.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 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.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; + } +}
\ No newline at end of file diff --git a/src/utils/lombok/javac/java8/CommentCollectingParserFactory.java b/src/utils/lombok/javac/java8/CommentCollectingParserFactory.java new file mode 100644 index 00000000..6b5f9198 --- /dev/null +++ b/src/utils/lombok/javac/java8/CommentCollectingParserFactory.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 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.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); + } + } +}
\ No newline at end of file diff --git a/src/utils/lombok/javac/java8/CommentCollectingScanner.java b/src/utils/lombok/javac/java8/CommentCollectingScanner.java new file mode 100644 index 00000000..b59a9390 --- /dev/null +++ b/src/utils/lombok/javac/java8/CommentCollectingScanner.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 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 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(); + } +}
\ No newline at end of file diff --git a/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java b/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java new file mode 100644 index 00000000..fa79ff67 --- /dev/null +++ b/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java @@ -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)); + } +} diff --git a/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java b/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java new file mode 100644 index 00000000..1834fb00 --- /dev/null +++ b/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 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 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 = new ListBuffer<CommentInfo>(); + 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; + } + } +}
\ No newline at end of file |