diff options
Diffstat (limited to 'src')
20 files changed, 253 insertions, 140 deletions
diff --git a/src/core/lombok/bytecode/ClassFileMetaData.java b/src/core/lombok/bytecode/ClassFileMetaData.java index 826eed83..0510292d 100644 --- a/src/core/lombok/bytecode/ClassFileMetaData.java +++ b/src/core/lombok/bytecode/ClassFileMetaData.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2018 The Project Lombok Authors. + * Copyright (C) 2010-2019 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 @@ -43,6 +43,7 @@ public class ClassFileMetaData { // New in java7: support for methodhandles and invokedynamic private static final byte METHOD_HANDLE = 15; private static final byte METHOD_TYPE = 16; + private static final byte DYNAMIC = 17; private static final byte INVOKE_DYNAMIC = 18; // New in java9: support for modules private static final byte MODULE = 19; @@ -96,6 +97,7 @@ public class ClassFileMetaData { case INTERFACE_METHOD: case NAME_TYPE: case INVOKE_DYNAMIC: + case DYNAMIC: position += 4; break; case LONG: @@ -388,6 +390,9 @@ public class ClassFileMetaData { case METHOD_TYPE: result.append("MethodType..."); break; + case DYNAMIC: + result.append("Dynamic..."); + break; case INVOKE_DYNAMIC: result.append("InvokeDynamic..."); break; diff --git a/src/core/lombok/core/LombokInternalAliasing.java b/src/core/lombok/core/LombokInternalAliasing.java index 68ced84f..60dea0f2 100644 --- a/src/core/lombok/core/LombokInternalAliasing.java +++ b/src/core/lombok/core/LombokInternalAliasing.java @@ -28,8 +28,6 @@ import java.util.HashMap; import java.util.Map; public class LombokInternalAliasing { - /** Maps a package name to a space separated list of packages. If the key package is star-imported, assume all packages in the 'value' part of the MapEntry are too. */ - public static final Map<String, Collection<String>> IMPLIED_EXTRA_STAR_IMPORTS; public static final Map<String, String> ALIASES; public static final Map<String, Collection<String>> REVERSE_ALIASES; @@ -43,36 +41,31 @@ public class LombokInternalAliasing { } static { - Map<String, Collection<String>> m1 = new HashMap<String, Collection<String>>(); - m1.put("lombok.experimental", Collections.singleton("lombok")); - m1.put("lombok", Collections.singleton("lombok.experimental")); - IMPLIED_EXTRA_STAR_IMPORTS = Collections.unmodifiableMap(m1); + Map<String, String> m1 = new HashMap<String, String>(); + m1.put("lombok.experimental.Value", "lombok.Value"); + m1.put("lombok.experimental.Builder", "lombok.Builder"); + m1.put("lombok.experimental.var", "lombok.var"); + m1.put("lombok.Delegate", "lombok.experimental.Delegate"); + m1.put("lombok.experimental.Wither", "lombok.With"); + ALIASES = Collections.unmodifiableMap(m1); - Map<String, String> m2 = new HashMap<String, String>(); - m2.put("lombok.experimental.Value", "lombok.Value"); - m2.put("lombok.experimental.Builder", "lombok.Builder"); - m2.put("lombok.experimental.var", "lombok.var"); - m2.put("lombok.Delegate", "lombok.experimental.Delegate"); - m2.put("lombok.experimental.Wither", "lombok.With"); - ALIASES = Collections.unmodifiableMap(m2); - - Map<String, Collection<String>> m3 = new HashMap<String, Collection<String>>(); - for (Map.Entry<String, String> e : m2.entrySet()) { - Collection<String> c = m3.get(e.getValue()); + Map<String, Collection<String>> m2 = new HashMap<String, Collection<String>>(); + for (Map.Entry<String, String> e : m1.entrySet()) { + Collection<String> c = m2.get(e.getValue()); if (c == null) { - m3.put(e.getValue(), Collections.singleton(e.getKey())); + m2.put(e.getValue(), Collections.singleton(e.getKey())); } else if (c.size() == 1) { Collection<String> newC = new ArrayList<String>(2); newC.addAll(c); - m3.put(e.getValue(), c); + m2.put(e.getValue(), c); } else { c.add(e.getKey()); } } - for (Map.Entry<String, Collection<String>> e : m3.entrySet()) { + for (Map.Entry<String, Collection<String>> e : m2.entrySet()) { Collection<String> c = e.getValue(); if (c.size() > 1) e.setValue(Collections.unmodifiableList((ArrayList<String>) c)); } - REVERSE_ALIASES = Collections.unmodifiableMap(m3); + REVERSE_ALIASES = Collections.unmodifiableMap(m2); } } diff --git a/src/core/lombok/core/TypeLibrary.java b/src/core/lombok/core/TypeLibrary.java index 113ce67e..8b9fa4b0 100644 --- a/src/core/lombok/core/TypeLibrary.java +++ b/src/core/lombok/core/TypeLibrary.java @@ -21,8 +21,11 @@ */ package lombok.core; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -36,18 +39,18 @@ import java.util.Map; * <ul><li>foo.Spork</li><li>Spork</li><li>foo.*</li></ul> */ public class TypeLibrary { - private final Map<String, String> unqualifiedToQualifiedMap; + private final Map<String, Object> unqualifiedToQualifiedMap; // maps to usually a string, but could be a string array in aliasing cases. private final String unqualified, qualified; private boolean locked; public TypeLibrary() { - unqualifiedToQualifiedMap = new HashMap<String, String>(); + unqualifiedToQualifiedMap = new HashMap<String, Object>(); unqualified = null; qualified = null; } public TypeLibrary(TypeLibrary parent) { - unqualifiedToQualifiedMap = new HashMap<String, String>(); + unqualifiedToQualifiedMap = new HashMap<String, Object>(); unqualified = null; qualified = null; } @@ -58,7 +61,7 @@ public class TypeLibrary { private TypeLibrary(String fqnSingleton) { if (fqnSingleton.indexOf("$") != -1) { - unqualifiedToQualifiedMap = new HashMap<String, String>(); + unqualifiedToQualifiedMap = new HashMap<String, Object>(); unqualified = null; qualified = null; addType(fqnSingleton); @@ -93,6 +96,9 @@ public class TypeLibrary { * @param fullyQualifiedTypeName the FQN type name, such as 'java.lang.String'. */ public void addType(String fullyQualifiedTypeName) { + Collection<String> oldNames = LombokInternalAliasing.REVERSE_ALIASES.get(fullyQualifiedTypeName); + if (oldNames != null) for (String oldName : oldNames) addType(oldName); + String dotBased = fullyQualifiedTypeName.replace("$", "."); if (locked) throw new IllegalStateException("locked"); @@ -102,22 +108,16 @@ public class TypeLibrary { String unqualified = fullyQualifiedTypeName.substring(idx + 1); if (unqualifiedToQualifiedMap == null) throw new IllegalStateException("SingleType library"); - unqualifiedToQualifiedMap.put(unqualified.replace("$", "."), dotBased); - unqualifiedToQualifiedMap.put(unqualified, dotBased); - unqualifiedToQualifiedMap.put(fullyQualifiedTypeName, dotBased); - unqualifiedToQualifiedMap.put(dotBased, dotBased); - Collection<String> oldNames = LombokInternalAliasing.REVERSE_ALIASES.get(fullyQualifiedTypeName); - if (oldNames != null) for (String oldName : oldNames) { - unqualifiedToQualifiedMap.put(oldName, dotBased); - int li = oldName.lastIndexOf('.'); - if (li != -1) unqualifiedToQualifiedMap.put(oldName.substring(li + 1), dotBased); - } + put(unqualified.replace("$", "."), dotBased); + put(unqualified, dotBased); + put(fullyQualifiedTypeName, dotBased); + put(dotBased, dotBased); int idx2 = fullyQualifiedTypeName.indexOf('$', idx + 1); while (idx2 != -1) { String unq = fullyQualifiedTypeName.substring(idx2 + 1); - unqualifiedToQualifiedMap.put(unq.replace("$", "."), dotBased); - unqualifiedToQualifiedMap.put(unq, dotBased); + put(unq.replace("$", "."), dotBased); + put(unq, dotBased); idx2 = fullyQualifiedTypeName.indexOf('$', idx2 + 1); } } @@ -126,13 +126,33 @@ public class TypeLibrary { * Translates an unqualified name such as 'String' to 'java.lang.String', _if_ you added 'java.lang.String' to the library via the {@code addType} method. * Also returns the input if it is equal to a fully qualified name added to this type library. * - * Returns null if it does not match any type in this type library. + * Returns an empty collection if it does not match any type in this type library. */ - public String toQualified(String typeReference) { + public List<String> toQualifieds(String typeReference) { if (unqualifiedToQualifiedMap == null) { - if (typeReference.equals(unqualified) || typeReference.equals(qualified)) return qualified; + if (typeReference.equals(unqualified) || typeReference.equals(qualified)) return Collections.singletonList(qualified); return null; } - return unqualifiedToQualifiedMap.get(typeReference); + + Object v = unqualifiedToQualifiedMap.get(typeReference); + if (v == null) return Collections.emptyList(); + if (v instanceof String) return Collections.singletonList((String) v); + return Arrays.asList((String[]) v); + } + + private void put(String k, String v) { + Object old = unqualifiedToQualifiedMap.put(k, v); + if (old == null) return; + String[] nv; + if (old instanceof String) { + if (old.equals(v)) return; + nv = new String[] {(String) old, v}; + } else { + String[] s = (String[]) old; + nv = new String[s.length + 1]; + System.arraycopy(s, 0, nv, 0, s.length); + nv[s.length] = v; + } + unqualifiedToQualifiedMap.put(k, nv); } } diff --git a/src/core/lombok/core/TypeResolver.java b/src/core/lombok/core/TypeResolver.java index 06c91138..2c36d1fc 100644 --- a/src/core/lombok/core/TypeResolver.java +++ b/src/core/lombok/core/TypeResolver.java @@ -21,6 +21,8 @@ */ package lombok.core; +import java.util.List; + import lombok.core.AST.Kind; /** @@ -44,13 +46,12 @@ public class TypeResolver { } public String typeRefToFullyQualifiedName(LombokNode<?, ?, ?> context, TypeLibrary library, String typeRef) { - typeRef = LombokInternalAliasing.processAliases(typeRef); // When asking if 'Foo' could possibly be referring to 'bar.Baz', the answer is obviously no. - String qualified = library.toQualified(typeRef); - if (qualified == null) return null; + List<String> qualifieds = library.toQualifieds(typeRef); + if (qualifieds == null || qualifieds.isEmpty()) return null; // When asking if 'lombok.Getter' could possibly be referring to 'lombok.Getter', the answer is obviously yes. - if (typeRef.equals(qualified)) return typeRef; + if (qualifieds.contains(typeRef)) return LombokInternalAliasing.processAliases(typeRef); // When asking if 'Getter' could possibly be referring to 'lombok.Getter' if 'import lombok.Getter;' is in the source file, the answer is yes. int firstDot = typeRef.indexOf('.'); @@ -58,50 +59,58 @@ public class TypeResolver { String firstTypeRef = typeRef.substring(0, firstDot); String fromExplicitImport = imports.getFullyQualifiedNameForSimpleName(firstTypeRef); if (fromExplicitImport != null) { + String fqn = fromExplicitImport + typeRef.substring(firstDot); + if (qualifieds.contains(fqn)) return LombokInternalAliasing.processAliases(fqn); // ... and if 'import foobar.Getter;' is in the source file, the answer is no. - return (fromExplicitImport + typeRef.substring(firstDot)).equals(qualified) ? qualified : null; + return null; } // When asking if 'Getter' could possibly be referring to 'lombok.Getter' and 'import lombok.*; / package lombok;' isn't in the source file. the answer is no. - String pkgName = qualified.substring(0, qualified.length() - typeRef.length() - 1); - if (!imports.hasStarImport(pkgName)) return null; - - // Now the hard part: Given that there is a star import, 'Getter' most likely refers to 'lombok.Getter', but type shadowing may occur in which case it doesn't. - LombokNode<?, ?, ?> n = context; - - mainLoop: - while (n != null) { - if (n.getKind() == Kind.TYPE && firstTypeRef.equals(n.getName())) { - // Our own class or one of our outer classes is named 'typeRef' so that's what 'typeRef' is referring to, not one of our type library classes. - return null; - } + for (String qualified : qualifieds) { + String pkgName = qualified.substring(0, qualified.length() - typeRef.length() - 1); + if (!imports.hasStarImport(pkgName)) continue; - if (n.getKind() == Kind.STATEMENT || n.getKind() == Kind.LOCAL) { - LombokNode<?, ?, ?> newN = n.directUp(); - if (newN == null) break mainLoop; + // Now the hard part: Given that there is a star import, 'Getter' most likely refers to 'lombok.Getter', but type shadowing may occur in which case it doesn't. + LombokNode<?, ?, ?> n = context; + + mainLoop: + while (n != null) { + if (n.getKind() == Kind.TYPE && firstTypeRef.equals(n.getName())) { + // Our own class or one of our outer classes is named 'typeRef' so that's what 'typeRef' is referring to, not one of our type library classes. + return null; + } - if (newN.getKind() == Kind.STATEMENT || newN.getKind() == Kind.INITIALIZER || newN.getKind() == Kind.METHOD) { - for (LombokNode<?, ?, ?> child : newN.down()) { - // We found a method local with the same name above our code. That's the one 'typeRef' is referring to, not - // anything in the type library we're trying to find, so, no matches. - if (child.getKind() == Kind.TYPE && firstTypeRef.equals(child.getName())) return null; - if (child == n) break; + if (n.getKind() == Kind.STATEMENT || n.getKind() == Kind.LOCAL) { + LombokNode<?, ?, ?> newN = n.directUp(); + if (newN == null) break mainLoop; + + if (newN.getKind() == Kind.STATEMENT || newN.getKind() == Kind.INITIALIZER || newN.getKind() == Kind.METHOD) { + for (LombokNode<?, ?, ?> child : newN.down()) { + // We found a method local with the same name above our code. That's the one 'typeRef' is referring to, not + // anything in the type library we're trying to find, so, no matches. + if (child.getKind() == Kind.TYPE && firstTypeRef.equals(child.getName())) return null; + if (child == n) break; + } } + n = newN; + continue mainLoop; } - n = newN; - continue mainLoop; - } - - if (n.getKind() == Kind.TYPE || n.getKind() == Kind.COMPILATION_UNIT) { - for (LombokNode<?, ?, ?> child : n.down()) { - // Inner class that's visible to us has 'typeRef' as name, so that's the one being referred to, not one of our type library classes. - if (child.getKind() == Kind.TYPE && firstTypeRef.equals(child.getName())) return null; + + if (n.getKind() == Kind.TYPE || n.getKind() == Kind.COMPILATION_UNIT) { + for (LombokNode<?, ?, ?> child : n.down()) { + // Inner class that's visible to us has 'typeRef' as name, so that's the one being referred to, not one of our type library classes. + if (child.getKind() == Kind.TYPE && firstTypeRef.equals(child.getName())) return null; + } } + + n = n.directUp(); } - n = n.directUp(); + // If no shadowing thing has been found, the star import 'wins', so, return that. + return LombokInternalAliasing.processAliases(qualified); } - return qualified; + // No star import matches either. + return null; } } diff --git a/src/core/lombok/eclipse/EclipseImportList.java b/src/core/lombok/eclipse/EclipseImportList.java index 47167ec6..6d60f5aa 100644 --- a/src/core/lombok/eclipse/EclipseImportList.java +++ b/src/core/lombok/eclipse/EclipseImportList.java @@ -27,7 +27,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Map; import lombok.core.ImportList; import lombok.core.LombokInternalAliasing; @@ -65,19 +64,10 @@ public class EclipseImportList implements ImportList { if (isEqual(packageName, pkg)) return true; if ("java.lang".equals(packageName)) return true; - if (pkg != null && pkg.tokens != null && pkg.tokens.length == 0) { - for (Map.Entry<String, Collection<String>> e : LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.entrySet()) { - if (isEqual(e.getKey(), pkg) && e.getValue().contains(packageName)) return true; - } - } - if (imports != null) for (ImportReference imp : imports) { if ((imp.bits & ASTNode.OnDemand) == 0) continue; if (imp.isStatic()) continue; if (isEqual(packageName, imp)) return true; - for (Map.Entry<String, Collection<String>> e : LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.entrySet()) { - if (isEqual(e.getKey(), imp) && e.getValue().contains(packageName)) return true; - } } return false; diff --git a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java index 0f463ae2..ce5a1b4c 100755 --- a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java +++ b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java @@ -109,7 +109,9 @@ public class EclipseSingularsRecipes { } public String toQualified(String typeReference) { - return singularizableTypes.toQualified(typeReference); + List<String> q = singularizableTypes.toQualifieds(typeReference); + if (q.isEmpty()) return null; + return q.get(0); } public EclipseSingularizer getSingularizer(String fqn) { diff --git a/src/core/lombok/javac/JavacImportList.java b/src/core/lombok/javac/JavacImportList.java index 468d8c7b..8de61afc 100644 --- a/src/core/lombok/javac/JavacImportList.java +++ b/src/core/lombok/javac/JavacImportList.java @@ -60,11 +60,6 @@ public class JavacImportList implements ImportList { if (pkgStr != null && pkgStr.equals(packageName)) return true; if ("java.lang".equals(packageName)) return true; - if (pkgStr != null) { - Collection<String> extra = LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.get(pkgStr); - if (extra != null && extra.contains(packageName)) return true; - } - for (JCTree def : defs) { if (!(def instanceof JCImport)) continue; if (((JCImport) def).staticImport) continue; @@ -74,8 +69,6 @@ public class JavacImportList implements ImportList { if (!"*".equals(simpleName)) continue; String starImport = ((JCFieldAccess) qual).selected.toString(); if (packageName.equals(starImport)) return true; - Collection<String> extra = LombokInternalAliasing.IMPLIED_EXTRA_STAR_IMPORTS.get(starImport); - if (extra != null && extra.contains(packageName)) return true; } return false; diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index 10e6f9b4..87081dde 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -101,7 +101,9 @@ public class JavacSingularsRecipes { } public String toQualified(String typeReference) { - return singularizableTypes.toQualified(typeReference); + java.util.List<String> q = singularizableTypes.toQualifieds(typeReference); + if (q.isEmpty()) return null; + return q.get(0); } public JavacSingularizer getSingularizer(String fqn, JavacNode node) { diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index 76b2715a..7318a8ce 100755 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2018 The Project Lombok Authors. + * Copyright (C) 2009-2019 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 @@ -700,11 +700,12 @@ public class Delombok { String[] argv = argsList.toArray(new String[0]); args.init("javac", argv); options.put("diags.legacy", "TRUE"); + options.put("allowStringFolding", "FALSE"); } else { if (modulepath != null && !modulepath.isEmpty()) throw new IllegalStateException("DELOMBOK: Option --module-path requires usage of JDK9 or higher."); } - CommentCatcher catcher = CommentCatcher.create(context); + CommentCatcher catcher = CommentCatcher.create(context, Javac.getJavaCompilerVersion() >= 13); JavaCompiler compiler = catcher.getCompiler(); List<JCCompilationUnit> roots = new ArrayList<JCCompilationUnit>(); @@ -769,7 +770,7 @@ public class Delombok { FormatPreferences fps = new FormatPreferences(formatPrefs); for (JCCompilationUnit unit : roots) { - DelombokResult result = new DelombokResult(catcher.getComments(unit), unit, force || options.isChanged(unit), fps); + DelombokResult result = new DelombokResult(catcher.getComments(unit), catcher.getTextBlockStarts(unit), unit, force || options.isChanged(unit), fps); if (onlyChanged && !result.isChanged() && !options.isChanged(unit)) { if (verbose) feedback.printf("File: %s [%s]\n", unit.sourcefile.getName(), "unchanged (skipped)"); continue; diff --git a/src/delombok/lombok/delombok/DelombokResult.java b/src/delombok/lombok/delombok/DelombokResult.java index 8985b257..bc19c74d 100644 --- a/src/delombok/lombok/delombok/DelombokResult.java +++ b/src/delombok/lombok/delombok/DelombokResult.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2013 The Project Lombok Authors. + * Copyright (C) 2009-2019 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 @@ -34,12 +34,14 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; public class DelombokResult { private final List<CommentInfo> comments; + private final List<Integer> textBlockStarts; private final JCCompilationUnit compilationUnit; private final boolean changed; private final FormatPreferences formatPreferences; - public DelombokResult(List<CommentInfo> comments, JCCompilationUnit compilationUnit, boolean changed, FormatPreferences formatPreferences) { + public DelombokResult(List<CommentInfo> comments, List<Integer> textBlockStarts, JCCompilationUnit compilationUnit, boolean changed, FormatPreferences formatPreferences) { this.comments = comments; + this.textBlockStarts = textBlockStarts; this.compilationUnit = compilationUnit; this.changed = changed; this.formatPreferences = formatPreferences; @@ -61,12 +63,15 @@ public class DelombokResult { } com.sun.tools.javac.util.List<CommentInfo> comments_; + int[] textBlockStarts_; if (comments instanceof com.sun.tools.javac.util.List) comments_ = (com.sun.tools.javac.util.List<CommentInfo>) comments; else comments_ = com.sun.tools.javac.util.List.from(comments.toArray(new CommentInfo[0])); - + textBlockStarts_ = new int[textBlockStarts.size()]; + int idx = 0; + for (int tbs : textBlockStarts) textBlockStarts_[idx++] = tbs; FormatPreferences preferences = new FormatPreferenceScanner().scan(formatPreferences, getContent()); //compilationUnit.accept(new PrettyCommentsPrinter(out, compilationUnit, comments_, preferences)); - compilationUnit.accept(new PrettyPrinter(out, compilationUnit, comments_, preferences)); + compilationUnit.accept(new PrettyPrinter(out, compilationUnit, comments_, textBlockStarts_, preferences)); } private CharSequence getContent() throws IOException { diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index 1532319f..fc5eaec2 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -31,6 +31,7 @@ import java.io.Writer; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -153,6 +154,7 @@ public class PrettyPrinter extends JCTree.Visitor { private final Writer out; private final JCCompilationUnit compilationUnit; private List<CommentInfo> comments; + private final int[] textBlockStarts; private final FormatPreferences formatPreferences; private final Map<JCTree, String> docComments; @@ -160,9 +162,10 @@ public class PrettyPrinter extends JCTree.Visitor { private int indent = 0; @SuppressWarnings({"unchecked", "rawtypes"}) - public PrettyPrinter(Writer out, JCCompilationUnit cu, List<CommentInfo> comments, FormatPreferences preferences) { + public PrettyPrinter(Writer out, JCCompilationUnit cu, List<CommentInfo> comments, int[] textBlockStarts, FormatPreferences preferences) { this.out = out; this.comments = comments; + this.textBlockStarts = textBlockStarts; this.compilationUnit = cu; this.formatPreferences = preferences; @@ -488,6 +491,19 @@ public class PrettyPrinter extends JCTree.Visitor { } @Override public void visitImport(JCImport tree) { + if (tree.qualid instanceof JCFieldAccess) { + JCFieldAccess fa = ((JCFieldAccess) tree.qualid); + if (fa.name.length() == 1 && fa.name.contentEquals("*")) { + if (fa.selected instanceof JCFieldAccess) { + JCFieldAccess lombokExperimental = (JCFieldAccess) fa.selected; + if (lombokExperimental.name.contentEquals("experimental") && lombokExperimental.selected instanceof JCIdent && ((JCIdent) lombokExperimental.selected).name.contentEquals("lombok")) { + // do not ever print lombok.experimental.*. + return; + } + } + } + } + aPrint("import "); if (tree.staticImport) print("static "); print(tree.qualid); @@ -727,7 +743,37 @@ public class PrettyPrinter extends JCTree.Visitor { } else if (CTC_BOOLEAN.equals(typeTag)) print(((Number)tree.value).intValue() == 1 ? "true" : "false"); else if (CTC_BOT.equals(typeTag)) print("null"); - else print("\"" + quoteChars(tree.value.toString()) + "\""); + else { + if (Arrays.binarySearch(textBlockStarts, tree.pos) < 0) { + print("\"" + quoteChars(tree.value.toString()) + "\""); + } else { + printTextBlock(tree.value.toString()); + } + } + } + + private void printTextBlock(String s) { + println("\"\"\""); + needsAlign = true; + indent++; + StringBuilder sb = new StringBuilder(); + boolean lineStart = true; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c != ' ' && c != '\t') lineStart = false; + if (c == '\n') { + println(sb); + sb.setLength(0); + needsAlign = true; + lineStart = true; + continue; + } + if (c == '\t' && lineStart) sb.append("\t"); + else sb.append(quoteChar(s.charAt(i))); + } + print(sb); + print("\"\"\""); + indent--; } @Override public void visitMethodDef(JCMethodDecl tree) { @@ -1266,6 +1312,11 @@ public class PrettyPrinter extends JCTree.Visitor { print(";"); needsNewLine = true; needsAlign = true; + } else if (tree.stats.head.getClass().getSimpleName().equals("JCYield")) { + print((JCExpression) readObject(tree.stats.head, "value", null)); + print(";"); + needsNewLine = true; + needsAlign = true; } else { print(tree.stats.head); if (tree.stats.head instanceof JCBlock) needsNewLine = false; @@ -1295,7 +1346,10 @@ public class PrettyPrinter extends JCTree.Visitor { print(")"); } println(" {"); + boolean ruleStyle = isCaseRuleStyle(tree.cases.head); + if (ruleStyle) indent++; print(tree.cases, ""); + if (ruleStyle) indent--; aPrintln("}", tree); } @@ -1311,10 +1365,20 @@ public class PrettyPrinter extends JCTree.Visitor { } println(" {"); List<JCCase> cases = readObject(tree, "cases", null); + boolean ruleStyle = isCaseRuleStyle(cases.head); + if (ruleStyle) indent++; print(cases, ""); + if (ruleStyle) indent--; aPrint("}"); } + void printYieldExpression(JCTree tree) { + aPrint("yield "); + JCExpression value = readObject(tree, "value", null); + print(value); + println(";", tree); + } + @Override public void visitTry(JCTry tree) { aPrint("try "); List<?> resources = readObject(tree, "resources", List.nil()); @@ -1535,11 +1599,19 @@ public class PrettyPrinter extends JCTree.Visitor { // Starting with JDK9, this is inside the import list, but we've already printed it. Just ignore it. } else if ("JCSwitchExpression".equals(simpleName)) { // Introduced as preview feature in JDK12 printSwitchExpression(tree); + } else if ("JCYield".equals(simpleName)) { // Introduced as preview feature in JDK13, part of switch expressions. + printYieldExpression(tree); } else { throw new AssertionError("Unhandled tree type: " + tree.getClass() + ": " + tree); } } + private boolean isCaseRuleStyle(JCCase tree) { + if (tree == null) return false; + Enum<?> caseKind = readObject(tree, "caseKind", null); // JDK 12+ + return caseKind != null && caseKind.name().equalsIgnoreCase("RULE"); + } + private boolean jcAnnotatedTypeInit = false; private Class<?> jcAnnotatedTypeClass = null; diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index 5c31e87a..056852c8 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -24,7 +24,6 @@ package lombok.eclipse.agent; import lombok.permit.Permit; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -54,7 +53,6 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; -import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; import java.lang.reflect.Field; @@ -455,7 +453,7 @@ public class PatchVal { } } - private static Field getField(Class clazz, String name) { + private static Field getField(Class<?> clazz, String name) { try { return Permit.getField(clazz, name); } catch (NoSuchFieldException e) { diff --git a/src/installer/lombok/installer/eclipse/EclipseProductLocation.java b/src/installer/lombok/installer/eclipse/EclipseProductLocation.java index aa97a3e5..73f98a35 100644 --- a/src/installer/lombok/installer/eclipse/EclipseProductLocation.java +++ b/src/installer/lombok/installer/eclipse/EclipseProductLocation.java @@ -294,10 +294,12 @@ public final class EclipseProductLocation extends IdeLocation { try { lombokJar.delete(); } catch (Throwable ignore) { /* Nothing we can do about that. */ } - if (!readSucceeded) throw new InstallException( - "I can't read my own jar file. I think you've found a bug in this installer!\nI suggest you restart it " + + if (!readSucceeded) { + throw new InstallException( + "I can't read my own jar file (trying: " + ourJar.toString() + "). I think you've found a bug in this installer!\nI suggest you restart it " + "and use the 'what do I do' link, to manually install lombok. Also, tell us about this at:\n" + - "http://groups.google.com/group/project-lombok - Thanks!", e); + "http://groups.google.com/group/project-lombok - Thanks!\n\n[DEBUG INFO] " + e.getClass() + ": " + e.getMessage() + "\nBase: " + OsUtils.class.getResource("OsUtils.class"), e); + } throw new InstallException("I can't write to your " + descriptor.getProductName() + " directory at " + name + generateWriteErrorMessage(), e); } } diff --git a/src/stubs/com/sun/tools/javac/parser/Tokens.java b/src/stubs/com/sun/tools/javac/parser/Tokens.java index 6e0aa479..f86bcefa 100644 --- a/src/stubs/com/sun/tools/javac/parser/Tokens.java +++ b/src/stubs/com/sun/tools/javac/parser/Tokens.java @@ -2,7 +2,7 @@ package com.sun.tools.javac.parser; public class Tokens { public static class Token { - + public int pos; } public interface Comment { diff --git a/src/utils/lombok/javac/CommentCatcher.java b/src/utils/lombok/javac/CommentCatcher.java index f8b73b0a..90266c26 100644 --- a/src/utils/lombok/javac/CommentCatcher.java +++ b/src/utils/lombok/javac/CommentCatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 The Project Lombok Authors. + * Copyright (C) 2011-2019 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 @@ -35,9 +35,10 @@ import com.sun.tools.javac.util.Context; public class CommentCatcher { private final JavaCompiler compiler; public static final FieldAugment<JCCompilationUnit, List<CommentInfo>> JCCompilationUnit_comments = FieldAugment.augment(JCCompilationUnit.class, List.class, "lombok$comments"); + public static final FieldAugment<JCCompilationUnit, List<Integer>> JCCompilationUnit_textBlockStarts = FieldAugment.augment(JCCompilationUnit.class, List.class, "lombok$textBlockStarts"); - public static CommentCatcher create(Context context) { - registerCommentsCollectingScannerFactory(context); + public static CommentCatcher create(Context context, boolean findTextBlocks) { + registerCommentsCollectingScannerFactory(context, findTextBlocks); JavaCompiler compiler = new JavaCompiler(context); setInCompiler(compiler, context); @@ -69,7 +70,12 @@ public class CommentCatcher { return list == null ? Collections.<CommentInfo>emptyList() : list; } - private static void registerCommentsCollectingScannerFactory(Context context) { + public List<Integer> getTextBlockStarts(JCCompilationUnit ast) { + List<Integer> list = JCCompilationUnit_textBlockStarts.get(ast); + return list == null ? Collections.<Integer>emptyList() : list; + } + + private static void registerCommentsCollectingScannerFactory(Context context, boolean findTextBlocks) { try { Class<?> scannerFactory; int javaCompilerVersion = Javac.getJavaCompilerVersion(); @@ -79,6 +85,7 @@ public class CommentCatcher { scannerFactory = Class.forName("lombok.javac.java7.CommentCollectingScannerFactory"); } else { scannerFactory = Class.forName("lombok.javac.java8.CommentCollectingScannerFactory"); + if (findTextBlocks) Permit.getField(scannerFactory, "findTextBlocks").set(null, true); } Permit.getMethod(scannerFactory, "preRegister", Context.class).invoke(null, context); } catch (InvocationTargetException e) { diff --git a/src/utils/lombok/javac/java8/CommentCollectingParser.java b/src/utils/lombok/javac/java8/CommentCollectingParser.java index b49312cb..c1dc2f7e 100644 --- a/src/utils/lombok/javac/java8/CommentCollectingParser.java +++ b/src/utils/lombok/javac/java8/CommentCollectingParser.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 The Project Lombok Authors. + * Copyright (C) 2013-2019 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 @@ -22,10 +22,7 @@ package lombok.javac.java8; import static lombok.javac.CommentCatcher.JCCompilationUnit_comments; - -import java.util.List; - -import lombok.javac.CommentInfo; +import static lombok.javac.CommentCatcher.JCCompilationUnit_textBlockStarts; import com.sun.tools.javac.parser.JavacParser; import com.sun.tools.javac.parser.Lexer; @@ -44,8 +41,8 @@ class CommentCollectingParser extends JavacParser { public JCCompilationUnit parseCompilationUnit() { JCCompilationUnit result = super.parseCompilationUnit(); if (lexer instanceof CommentCollectingScanner) { - List<CommentInfo> comments = ((CommentCollectingScanner)lexer).getComments(); - JCCompilationUnit_comments.set(result, comments); + JCCompilationUnit_comments.set(result, ((CommentCollectingScanner) lexer).getComments()); + JCCompilationUnit_textBlockStarts.set(result, ((CommentCollectingScanner) lexer).getTextBlockStarts()); } return result; } diff --git a/src/utils/lombok/javac/java8/CommentCollectingScanner.java b/src/utils/lombok/javac/java8/CommentCollectingScanner.java index b59a9390..5a0647cc 100644 --- a/src/utils/lombok/javac/java8/CommentCollectingScanner.java +++ b/src/utils/lombok/javac/java8/CommentCollectingScanner.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Project Lombok Authors. + * Copyright (C) 2013-2019 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 @@ -39,4 +39,8 @@ public class CommentCollectingScanner extends Scanner { public List<CommentInfo> getComments() { return tokenizer.getComments(); } + + public List<Integer> getTextBlockStarts() { + return tokenizer.getTextBlockStarts(); + } }
\ No newline at end of file diff --git a/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java b/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java index fa79ff67..cb0d2e12 100644 --- a/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java +++ b/src/utils/lombok/javac/java8/CommentCollectingScannerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 The Project Lombok Authors. + * Copyright (C) 2011-2019 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 @@ -28,7 +28,7 @@ import com.sun.tools.javac.parser.ScannerFactory; import com.sun.tools.javac.util.Context; public class CommentCollectingScannerFactory extends ScannerFactory { - + public static boolean findTextBlocks; @SuppressWarnings("all") public static void preRegister(final Context context) { if (context.get(scannerFactoryKey) == null) { @@ -76,7 +76,7 @@ public class CommentCollectingScannerFactory extends ScannerFactory { public Scanner newScanner(CharSequence input, boolean keepDocComments) { if (input instanceof CharBuffer) { CharBuffer buf = (CharBuffer) input; - return new CommentCollectingScanner(this, new CommentCollectingTokenizer(this, buf)); + return new CommentCollectingScanner(this, new CommentCollectingTokenizer(this, buf, findTextBlocks)); } char[] array = input.toString().toCharArray(); return newScanner(array, array.length, keepDocComments); @@ -84,6 +84,6 @@ public class CommentCollectingScannerFactory extends ScannerFactory { @Override public Scanner newScanner(char[] input, int inputLength, boolean keepDocComments) { - return new CommentCollectingScanner(this, new CommentCollectingTokenizer(this, input, inputLength)); + return new CommentCollectingScanner(this, new CommentCollectingTokenizer(this, input, inputLength, findTextBlocks)); } } diff --git a/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java b/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java index 1834fb00..08477e61 100644 --- a/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java +++ b/src/utils/lombok/javac/java8/CommentCollectingTokenizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Project Lombok Authors. + * Copyright (C) 2013-2019 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 @@ -39,19 +39,30 @@ import com.sun.tools.javac.util.ListBuffer; class CommentCollectingTokenizer extends JavaTokenizer { private int prevEndPosition = 0; private final ListBuffer<CommentInfo> comments = new ListBuffer<CommentInfo>(); + private final ListBuffer<Integer> textBlockStarts; private int endComment = 0; - - CommentCollectingTokenizer(ScannerFactory fac, char[] buf, int inputLength) { + + CommentCollectingTokenizer(ScannerFactory fac, char[] buf, int inputLength, boolean findTextBlocks) { super(fac, new PositionUnicodeReader(fac, buf, inputLength)); + textBlockStarts = findTextBlocks ? new ListBuffer<Integer>() : null; } - CommentCollectingTokenizer(ScannerFactory fac, CharBuffer buf) { + CommentCollectingTokenizer(ScannerFactory fac, CharBuffer buf, boolean findTextBlocks) { super(fac, new PositionUnicodeReader(fac, buf)); + textBlockStarts = findTextBlocks ? new ListBuffer<Integer>() : null; + } + + int pos() { + return ((PositionUnicodeReader) reader).pos(); } @Override public Token readToken() { Token token = super.readToken(); - prevEndPosition = ((PositionUnicodeReader)reader).pos(); + prevEndPosition = pos(); + if (textBlockStarts != null && (prevEndPosition - token.pos > 5) && token.getClass().getSimpleName().equals("StringToken")) { + char[] start = reader.getRawCharacters(token.pos, token.pos + 3); + if (start[0] == '"' && start[1] == '"' && start[2] == '"') textBlockStarts.add(token.pos); + } return token; } @@ -113,6 +124,10 @@ class CommentCollectingTokenizer extends JavaTokenizer { return comments.toList(); } + public List<Integer> getTextBlockStarts() { + return textBlockStarts == null ? List.<Integer>nil() : textBlockStarts.toList(); + } + static class PositionUnicodeReader extends UnicodeReader { protected PositionUnicodeReader(ScannerFactory sf, char[] input, int inputLength) { super(sf, input, inputLength); diff --git a/src/utils/lombok/javac/java9/CommentCollectingParser.java b/src/utils/lombok/javac/java9/CommentCollectingParser.java index 307be405..034b6705 100644 --- a/src/utils/lombok/javac/java9/CommentCollectingParser.java +++ b/src/utils/lombok/javac/java9/CommentCollectingParser.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2017 The Project Lombok Authors. + * Copyright (C) 2013-2019 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 @@ -22,10 +22,8 @@ package lombok.javac.java9; import static lombok.javac.CommentCatcher.JCCompilationUnit_comments; +import static lombok.javac.CommentCatcher.JCCompilationUnit_textBlockStarts; -import java.util.List; - -import lombok.javac.CommentInfo; import lombok.javac.java8.CommentCollectingScanner; import com.sun.tools.javac.parser.JavacParser; @@ -45,8 +43,8 @@ class CommentCollectingParser extends JavacParser { public JCCompilationUnit parseCompilationUnit() { JCCompilationUnit result = super.parseCompilationUnit(); if (lexer instanceof CommentCollectingScanner) { - List<CommentInfo> comments = ((CommentCollectingScanner)lexer).getComments(); - JCCompilationUnit_comments.set(result, comments); + JCCompilationUnit_comments.set(result, ((CommentCollectingScanner) lexer).getComments()); + JCCompilationUnit_textBlockStarts.set(result, ((CommentCollectingScanner) lexer).getTextBlockStarts()); } return result; } |