diff options
Diffstat (limited to 'src')
41 files changed, 748 insertions, 302 deletions
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index dfcb3e33..2b406dbe 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -83,7 +83,7 @@ public class ConfigurationKeys { * * NB: If you enable this option, findbugs must be on the source or classpath, or you'll get errors that the type {@code SuppressFBWarnings} cannot be found. */ - public static final ConfigurationKey<Boolean> ADD_FINDBUGS_SUPPRESSWARNINGS_ANNOTATIONS = new ConfigurationKey<Boolean>("lombok.extern.findbugs.addSuppressFBWarnings", "Generate @edu.umd.cs.findbugs.annotations.SuppressFBWArnings on all generated code (default: false).") {}; + public static final ConfigurationKey<Boolean> ADD_FINDBUGS_SUPPRESSWARNINGS_ANNOTATIONS = new ConfigurationKey<Boolean>("lombok.extern.findbugs.addSuppressFBWarnings", "Generate @edu.umd.cs.findbugs.annotations.SuppressFBWarnings on all generated code (default: false).") {}; // ----- *ArgsConstructor ----- @@ -138,7 +138,7 @@ public class ConfigurationKeys { * * If {@code true} (default), @Data and @Value will also generate a private no-args constructor, if there isn't already one, setting all fields to their default values. */ - public static final ConfigurationKey<Boolean> NO_ARGS_CONSTRUCTOR_EXTRA_PRIVATE = new ConfigurationKey<Boolean>("lombok.noArgsConstructor.extraPrivate", "Generate a private no-ars constructor for @Data and @Value (default: true).") {}; + public static final ConfigurationKey<Boolean> NO_ARGS_CONSTRUCTOR_EXTRA_PRIVATE = new ConfigurationKey<Boolean>("lombok.noArgsConstructor.extraPrivate", "Generate a private no-args constructor for @Data and @Value (default: true).") {}; /** * lombok configuration: {@code lombok.requiredArgsConstructor.flagUsage} = {@code WARNING} | {@code ERROR}. diff --git a/src/core/lombok/core/AST.java b/src/core/lombok/core/AST.java index afbba1e8..78761f46 100644..100755 --- a/src/core/lombok/core/AST.java +++ b/src/core/lombok/core/AST.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2016 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 @@ -53,7 +53,7 @@ import lombok.permit.Permit; public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, N> { /** The kind of node represented by a given AST.Node object. */ public enum Kind { - COMPILATION_UNIT, TYPE, FIELD, INITIALIZER, METHOD, ANNOTATION, ARGUMENT, LOCAL, STATEMENT; + COMPILATION_UNIT, TYPE, FIELD, INITIALIZER, METHOD, ANNOTATION, ARGUMENT, LOCAL, STATEMENT, TYPE_USE; } private L top; @@ -229,7 +229,7 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, List<FieldAccess> fieldList = new ArrayList<FieldAccess>(); getFields(c, fieldList); - fieldsOfASTClasses.putIfAbsent(c, fieldList.toArray(new FieldAccess[fieldList.size()])); + fieldsOfASTClasses.putIfAbsent(c, fieldList.toArray(new FieldAccess[0])); return fieldsOfASTClasses.get(c); } @@ -263,8 +263,8 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, private Class<?> getComponentType(Type type) { if (type instanceof ParameterizedType) { - Type component = ((ParameterizedType)type).getActualTypeArguments()[0]; - return component instanceof Class<?> ? (Class<?>)component : Object.class; + Type component = ((ParameterizedType) type).getActualTypeArguments()[0]; + return component instanceof Class<?> ? (Class<?>) component : Object.class; } return Object.class; } @@ -330,7 +330,7 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, idx++; if (o == null) continue; if (Collection.class.isInstance(o)) { - Collection<?> newC = (Collection<?>)o; + Collection<?> newC = (Collection<?>) o; List<Collection<?>> newChain = new ArrayList<Collection<?>>(chain); newChain.add(newC); if (replaceStatementInCollection(field, fieldRef, newChain, newC, oldN, newN)) return true; @@ -356,7 +356,7 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, @SuppressWarnings({"rawtypes", "unchecked"}) protected void setElementInASTCollection(Field field, Object fieldRef, List<Collection<?>> chain, Collection<?> collection, int idx, N newN) throws IllegalAccessException { if (collection instanceof List<?>) { - ((List)collection).set(idx, newN); + ((List) collection).set(idx, newN); } } @@ -384,7 +384,7 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, Object o = fa.field.get(child); if (o == null) return; if (fa.dim == 0) { - L node = buildTree((N)o, Kind.STATEMENT); + L node = buildTree((N) o, Kind.STATEMENT); if (node != null) list.add(nodeType.cast(node)); } else if (o.getClass().isArray()) { buildWithArray(nodeType, o, list, fa.dim); @@ -399,12 +399,12 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, @SuppressWarnings("unchecked") private void buildWithArray(Class<L> nodeType, Object array, Collection<L> list, int dim) { if (dim == 1) { - for (Object v : (Object[])array) { + for (Object v : (Object[]) array) { if (v == null) continue; L node = buildTree((N)v, Kind.STATEMENT); if (node != null) list.add(nodeType.cast(node)); } - } else for (Object v : (Object[])array) { + } else for (Object v : (Object[]) array) { if (v == null) return; buildWithArray(nodeType, v, list, dim -1); } @@ -413,13 +413,13 @@ public abstract class AST<A extends AST<A, L, N>, L extends LombokNode<A, L, N>, @SuppressWarnings("unchecked") private void buildWithCollection(Class<L> nodeType, Object collection, Collection<L> list, int dim) { if (dim == 1) { - for (Object v : (Collection<?>)collection) { + for (Object v : (Collection<?>) collection) { if (v == null) continue; - L node = buildTree((N)v, Kind.STATEMENT); + L node = buildTree((N) v, Kind.STATEMENT); if (node != null) list.add(nodeType.cast(node)); } - } else for (Object v : (Collection<?>)collection) { - buildWithCollection(nodeType, v, list, dim-1); + } else for (Object v : (Collection<?>) collection) { + buildWithCollection(nodeType, v, list, dim - 1); } } diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index ac91447d..1a92b5f6 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -79,29 +79,225 @@ public class HandlerUtil { public static final List<String> NONNULL_ANNOTATIONS, BASE_COPYABLE_ANNOTATIONS; static { NONNULL_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] { - "lombok.NonNull", - "javax.annotation.Nonnull", - "edu.umd.cs.findbugs.annotations.NonNull", - "org.jetbrains.annotations.NotNull", + "android.annotation.NonNull", "android.support.annotation.NonNull", + "com.sun.istack.internal.NotNull", + "edu.umd.cs.findbugs.annotations.NonNull", + "javax.annotation.Nonnull", + // The field might contain a null value until it is persisted. + // "javax.validation.constraints.NotNull", + "lombok.NonNull", + "org.checkerframework.checker.nullness.qual.NonNull", "org.eclipse.jdt.annotation.NonNull", + "org.eclipse.jgit.annotations.NonNull", + "org.jetbrains.annotations.NotNull", + "org.jmlspecs.annotation.NonNull", + "org.netbeans.api.annotations.common.NonNull", "org.springframework.lang.NonNull" })); BASE_COPYABLE_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] { - "lombok.NonNull", - "javax.annotation.Nonnull", - "edu.umd.cs.findbugs.annotations.NonNull", - "org.jetbrains.annotations.NotNull", "android.support.annotation.NonNull", - "org.eclipse.jdt.annotation.NonNull", - "org.springframework.lang.NonNull", - "javax.annotation.Nullable", - "javax.annotation.CheckForNull", - "edu.umd.cs.findbugs.annotations.UnknownNullness", - "edu.umd.cs.findbugs.annotations.Nullable", - "org.jetbrains.annotations.Nullable", "android.support.annotation.Nullable", + "edu.umd.cs.findbugs.annotations.NonNull", + "edu.umd.cs.findbugs.annotations.Nullable", + "edu.umd.cs.findbugs.annotations.UnknownNullness", + "javax.annotation.CheckForNull", + "javax.annotation.Nonnull", + "javax.annotation.Nullable", + "lombok.NonNull", + // To update Checker Framework annotations, run: + // grep --recursive --files-with-matches -e '^@Target\b.*TYPE_USE' $CHECKERFRAMEWORK/checker/src/main/java $CHECKERFRAMEWORK/framework/src/main/java | grep '\.java$' | sed 's/.*\/java\//\t\t\t"/' | sed 's/\.java$/",/' | sed 's/\//./g' | sort + "org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey", + "org.checkerframework.checker.compilermsgs.qual.CompilerMessageKeyBottom", + "org.checkerframework.checker.compilermsgs.qual.UnknownCompilerMessageKey", + "org.checkerframework.checker.fenum.qual.AwtAlphaCompositingRule", + "org.checkerframework.checker.fenum.qual.AwtColorSpace", + "org.checkerframework.checker.fenum.qual.AwtCursorType", + "org.checkerframework.checker.fenum.qual.AwtFlowLayout", + "org.checkerframework.checker.fenum.qual.Fenum", + "org.checkerframework.checker.fenum.qual.FenumBottom", + "org.checkerframework.checker.fenum.qual.FenumTop", + "org.checkerframework.checker.fenum.qual.PolyFenum", + "org.checkerframework.checker.fenum.qual.SwingBoxOrientation", + "org.checkerframework.checker.fenum.qual.SwingCompassDirection", + "org.checkerframework.checker.fenum.qual.SwingElementOrientation", + "org.checkerframework.checker.fenum.qual.SwingHorizontalOrientation", + "org.checkerframework.checker.fenum.qual.SwingSplitPaneOrientation", + "org.checkerframework.checker.fenum.qual.SwingTextOrientation", + "org.checkerframework.checker.fenum.qual.SwingTitleJustification", + "org.checkerframework.checker.fenum.qual.SwingTitlePosition", + "org.checkerframework.checker.fenum.qual.SwingVerticalOrientation", + "org.checkerframework.checker.formatter.qual.Format", + "org.checkerframework.checker.formatter.qual.FormatBottom", + "org.checkerframework.checker.formatter.qual.InvalidFormat", + "org.checkerframework.checker.guieffect.qual.AlwaysSafe", + "org.checkerframework.checker.guieffect.qual.PolyUI", + "org.checkerframework.checker.guieffect.qual.UI", + "org.checkerframework.checker.i18nformatter.qual.I18nFormat", + "org.checkerframework.checker.i18nformatter.qual.I18nFormatBottom", + "org.checkerframework.checker.i18nformatter.qual.I18nFormatFor", + "org.checkerframework.checker.i18nformatter.qual.I18nInvalidFormat", + "org.checkerframework.checker.i18nformatter.qual.I18nUnknownFormat", + "org.checkerframework.checker.i18n.qual.LocalizableKey", + "org.checkerframework.checker.i18n.qual.LocalizableKeyBottom", + "org.checkerframework.checker.i18n.qual.Localized", + "org.checkerframework.checker.i18n.qual.UnknownLocalizableKey", + "org.checkerframework.checker.i18n.qual.UnknownLocalized", + "org.checkerframework.checker.index.qual.GTENegativeOne", + "org.checkerframework.checker.index.qual.IndexFor", + "org.checkerframework.checker.index.qual.IndexOrHigh", + "org.checkerframework.checker.index.qual.IndexOrLow", + "org.checkerframework.checker.index.qual.LengthOf", + "org.checkerframework.checker.index.qual.LessThan", + "org.checkerframework.checker.index.qual.LessThanBottom", + "org.checkerframework.checker.index.qual.LessThanUnknown", + "org.checkerframework.checker.index.qual.LowerBoundBottom", + "org.checkerframework.checker.index.qual.LowerBoundUnknown", + "org.checkerframework.checker.index.qual.LTEqLengthOf", + "org.checkerframework.checker.index.qual.LTLengthOf", + "org.checkerframework.checker.index.qual.LTOMLengthOf", + "org.checkerframework.checker.index.qual.NegativeIndexFor", + "org.checkerframework.checker.index.qual.NonNegative", + "org.checkerframework.checker.index.qual.PolyIndex", + "org.checkerframework.checker.index.qual.PolyLength", + "org.checkerframework.checker.index.qual.PolyLowerBound", + "org.checkerframework.checker.index.qual.PolySameLen", + "org.checkerframework.checker.index.qual.PolyUpperBound", + "org.checkerframework.checker.index.qual.Positive", + "org.checkerframework.checker.index.qual.SameLen", + "org.checkerframework.checker.index.qual.SameLenBottom", + "org.checkerframework.checker.index.qual.SameLenUnknown", + "org.checkerframework.checker.index.qual.SearchIndexBottom", + "org.checkerframework.checker.index.qual.SearchIndexFor", + "org.checkerframework.checker.index.qual.SearchIndexUnknown", + "org.checkerframework.checker.index.qual.SubstringIndexBottom", + "org.checkerframework.checker.index.qual.SubstringIndexFor", + "org.checkerframework.checker.index.qual.SubstringIndexUnknown", + "org.checkerframework.checker.index.qual.UpperBoundBottom", + "org.checkerframework.checker.index.qual.UpperBoundUnknown", + "org.checkerframework.checker.initialization.qual.FBCBottom", + "org.checkerframework.checker.initialization.qual.Initialized", + "org.checkerframework.checker.initialization.qual.UnderInitialization", + "org.checkerframework.checker.initialization.qual.UnknownInitialization", + "org.checkerframework.checker.interning.qual.Interned", + "org.checkerframework.checker.interning.qual.InternedDistinct", + "org.checkerframework.checker.interning.qual.PolyInterned", + "org.checkerframework.checker.interning.qual.UnknownInterned", + "org.checkerframework.checker.lock.qual.GuardedBy", + "org.checkerframework.checker.lock.qual.GuardedByBottom", + "org.checkerframework.checker.lock.qual.GuardedByUnknown", + "org.checkerframework.checker.lock.qual.GuardSatisfied", + "org.checkerframework.checker.nullness.qual.KeyFor", + "org.checkerframework.checker.nullness.qual.KeyForBottom", + "org.checkerframework.checker.nullness.qual.MonotonicNonNull", + "org.checkerframework.checker.nullness.qual.NonNull", + "org.checkerframework.checker.nullness.qual.NonRaw", + "org.checkerframework.checker.nullness.qual.Nullable", + "org.checkerframework.checker.nullness.qual.PolyKeyFor", + "org.checkerframework.checker.nullness.qual.PolyNull", + "org.checkerframework.checker.nullness.qual.PolyRaw", + "org.checkerframework.checker.nullness.qual.Raw", + "org.checkerframework.checker.nullness.qual.UnknownKeyFor", + "org.checkerframework.checker.optional.qual.MaybePresent", + "org.checkerframework.checker.optional.qual.PolyPresent", + "org.checkerframework.checker.optional.qual.Present", + "org.checkerframework.checker.propkey.qual.PropertyKey", + "org.checkerframework.checker.propkey.qual.PropertyKeyBottom", + "org.checkerframework.checker.propkey.qual.UnknownPropertyKey", + "org.checkerframework.checker.regex.qual.PolyRegex", + "org.checkerframework.checker.regex.qual.Regex", + "org.checkerframework.checker.regex.qual.RegexBottom", + "org.checkerframework.checker.regex.qual.UnknownRegex", + "org.checkerframework.checker.signature.qual.BinaryName", + "org.checkerframework.checker.signature.qual.BinaryNameInUnnamedPackage", + "org.checkerframework.checker.signature.qual.ClassGetName", + "org.checkerframework.checker.signature.qual.ClassGetSimpleName", + "org.checkerframework.checker.signature.qual.DotSeparatedIdentifiers", + "org.checkerframework.checker.signature.qual.FieldDescriptor", + "org.checkerframework.checker.signature.qual.FieldDescriptorForPrimitive", + "org.checkerframework.checker.signature.qual.FieldDescriptorForPrimitiveOrArrayInUnnamedPackage", + "org.checkerframework.checker.signature.qual.FullyQualifiedName", + "org.checkerframework.checker.signature.qual.Identifier", + "org.checkerframework.checker.signature.qual.IdentifierOrArray", + "org.checkerframework.checker.signature.qual.InternalForm", + "org.checkerframework.checker.signature.qual.MethodDescriptor", + "org.checkerframework.checker.signature.qual.PolySignature", + "org.checkerframework.checker.signature.qual.SignatureBottom", + "org.checkerframework.checker.signedness.qual.Constant", + "org.checkerframework.checker.signedness.qual.PolySignedness", + "org.checkerframework.checker.signedness.qual.Signed", + "org.checkerframework.checker.signedness.qual.SignednessBottom", + "org.checkerframework.checker.signedness.qual.UnknownSignedness", + "org.checkerframework.checker.signedness.qual.Unsigned", + "org.checkerframework.checker.tainting.qual.PolyTainted", + "org.checkerframework.checker.tainting.qual.Tainted", + "org.checkerframework.checker.tainting.qual.Untainted", + "org.checkerframework.checker.units.qual.A", + "org.checkerframework.checker.units.qual.Acceleration", + "org.checkerframework.checker.units.qual.Angle", + "org.checkerframework.checker.units.qual.Area", + "org.checkerframework.checker.units.qual.C", + "org.checkerframework.checker.units.qual.cd", + "org.checkerframework.checker.units.qual.Current", + "org.checkerframework.checker.units.qual.degrees", + "org.checkerframework.checker.units.qual.g", + "org.checkerframework.checker.units.qual.h", + "org.checkerframework.checker.units.qual.K", + "org.checkerframework.checker.units.qual.kg", + "org.checkerframework.checker.units.qual.km", + "org.checkerframework.checker.units.qual.km2", + "org.checkerframework.checker.units.qual.kmPERh", + "org.checkerframework.checker.units.qual.Length", + "org.checkerframework.checker.units.qual.Luminance", + "org.checkerframework.checker.units.qual.m", + "org.checkerframework.checker.units.qual.m2", + "org.checkerframework.checker.units.qual.Mass", + "org.checkerframework.checker.units.qual.min", + "org.checkerframework.checker.units.qual.mm", + "org.checkerframework.checker.units.qual.mm2", + "org.checkerframework.checker.units.qual.mol", + "org.checkerframework.checker.units.qual.mPERs", + "org.checkerframework.checker.units.qual.mPERs2", + "org.checkerframework.checker.units.qual.PolyUnit", + "org.checkerframework.checker.units.qual.radians", + "org.checkerframework.checker.units.qual.s", + "org.checkerframework.checker.units.qual.Speed", + "org.checkerframework.checker.units.qual.Substance", + "org.checkerframework.checker.units.qual.Temperature", + "org.checkerframework.checker.units.qual.Time", + "org.checkerframework.checker.units.qual.UnitsBottom", + "org.checkerframework.checker.units.qual.UnknownUnits", + "org.checkerframework.common.aliasing.qual.LeakedToResult", + "org.checkerframework.common.aliasing.qual.MaybeAliased", + "org.checkerframework.common.aliasing.qual.NonLeaked", + "org.checkerframework.common.aliasing.qual.Unique", + "org.checkerframework.common.reflection.qual.ClassBound", + "org.checkerframework.common.reflection.qual.ClassVal", + "org.checkerframework.common.reflection.qual.ClassValBottom", + "org.checkerframework.common.reflection.qual.MethodVal", + "org.checkerframework.common.reflection.qual.MethodValBottom", + "org.checkerframework.common.reflection.qual.UnknownClass", + "org.checkerframework.common.reflection.qual.UnknownMethod", + "org.checkerframework.common.subtyping.qual.Bottom", + "org.checkerframework.common.util.report.qual.ReportUnqualified", + "org.checkerframework.common.value.qual.ArrayLen", + "org.checkerframework.common.value.qual.ArrayLenRange", + "org.checkerframework.common.value.qual.BoolVal", + "org.checkerframework.common.value.qual.BottomVal", + "org.checkerframework.common.value.qual.DoubleVal", + "org.checkerframework.common.value.qual.IntRange", + "org.checkerframework.common.value.qual.IntVal", + "org.checkerframework.common.value.qual.MinLen", + "org.checkerframework.common.value.qual.PolyValue", + "org.checkerframework.common.value.qual.StringVal", + "org.checkerframework.common.value.qual.UnknownVal", + "org.checkerframework.framework.qual.PolyAll", + "org.checkerframework.framework.util.PurityUnqualified", + "org.eclipse.jdt.annotation.NonNull", "org.eclipse.jdt.annotation.Nullable", + "org.jetbrains.annotations.NotNull", + "org.jetbrains.annotations.Nullable", + "org.springframework.lang.NonNull", "org.springframework.lang.Nullable" })); } diff --git a/src/core/lombok/eclipse/EclipseAST.java b/src/core/lombok/eclipse/EclipseAST.java index 1ba26338..e724fb50 100644 --- a/src/core/lombok/eclipse/EclipseAST.java +++ b/src/core/lombok/eclipse/EclipseAST.java @@ -22,6 +22,7 @@ package lombok.eclipse; import java.io.File; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; @@ -49,8 +50,12 @@ import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.ImportReference; import org.eclipse.jdt.internal.compiler.ast.Initializer; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.ast.Wildcard; /** * Wraps around Eclipse's internal AST view to add useful features as well as the ability to visit parents from children, @@ -292,7 +297,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { throw Lombok.sneakyThrow(e); } catch (NullPointerException e) { if (!"false".equals(System.getProperty("lombok.debug.reflection", "false"))) { - e.initCause(EcjReflectionCheck.problem); + e.initCause(EcjReflectionCheck.problemAddProblemToCompilationResult); throw e; } //ignore, we don't have access to the correct ECJ classes, so lombok can't possibly @@ -300,6 +305,25 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { } } + public static Annotation[] getTopLevelTypeReferenceAnnotations(TypeReference tr) { + Method m = EcjReflectionCheck.typeReferenceGetAnnotationsOnDimensions; + if (m == null) return null; + Annotation[][] annss = null; + try { + annss = (Annotation[][]) m.invoke(tr); + if (annss != null) return annss[0]; + } catch (Throwable ignore) {} + + try { + Field f = EcjReflectionCheck.typeReferenceAnnotations; + if (f == null) return null; + annss = (Annotation[][]) f.get(tr); + return annss[annss.length - 1]; + } catch (Throwable t) { + return null; + } + } + private final CompilationUnitDeclaration compilationUnitDeclaration; private boolean completeParse; @@ -350,6 +374,8 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { return buildStatement((Statement) node); case ANNOTATION: return buildAnnotation((Annotation) node, false); + case TYPE_USE: + return buildTypeUse((TypeReference) node); default: throw new AssertionError("Did not expect to arrive here: " + kind); } @@ -397,6 +423,7 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { if (field instanceof Initializer) return buildInitializer((Initializer)field); if (setAndGetAsHandled(field)) return null; List<EclipseNode> childNodes = new ArrayList<EclipseNode>(); + addIfNotNull(childNodes, buildTypeUse(field.type)); addIfNotNull(childNodes, buildStatement(field.initialization)); childNodes.addAll(buildAnnotations(field.annotations, true)); return putInMap(new EclipseNode(this, field, childNodes, Kind.FIELD)); @@ -438,11 +465,40 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { private EclipseNode buildLocal(LocalDeclaration local, Kind kind) { if (setAndGetAsHandled(local)) return null; List<EclipseNode> childNodes = new ArrayList<EclipseNode>(); + addIfNotNull(childNodes, buildTypeUse(local.type)); addIfNotNull(childNodes, buildStatement(local.initialization)); childNodes.addAll(buildAnnotations(local.annotations, true)); return putInMap(new EclipseNode(this, local, childNodes, kind)); } + private EclipseNode buildTypeUse(TypeReference tr) { + if (setAndGetAsHandled(tr)) return null; + if (tr == null) return null; + + List<EclipseNode> childNodes = new ArrayList<EclipseNode>(); + Annotation[] anns = getTopLevelTypeReferenceAnnotations(tr); + if (anns != null) for (Annotation ann : anns) addIfNotNull(childNodes, buildAnnotation(ann, false)); + + if (tr instanceof ParameterizedQualifiedTypeReference) { + ParameterizedQualifiedTypeReference pqtr = (ParameterizedQualifiedTypeReference) tr; + int len = pqtr.tokens.length; + for (int i = 0; i < len; i++) { + TypeReference[] typeArgs = pqtr.typeArguments[i]; + if (typeArgs != null) for (TypeReference tArg : typeArgs) addIfNotNull(childNodes, buildTypeUse(tArg)); + } + } else if (tr instanceof ParameterizedSingleTypeReference) { + ParameterizedSingleTypeReference pstr = (ParameterizedSingleTypeReference) tr; + if (pstr.typeArguments != null) for (TypeReference tArg : pstr.typeArguments) { + addIfNotNull(childNodes, buildTypeUse(tArg)); + } + } else if (tr instanceof Wildcard) { + TypeReference bound = ((Wildcard) tr).bound; + if (bound != null) addIfNotNull(childNodes, buildTypeUse(bound)); + } + + return putInMap(new EclipseNode(this, tr, childNodes, Kind.TYPE_USE)); + } + private Collection<EclipseNode> buildAnnotations(Annotation[] annotations, boolean varDecl) { List<EclipseNode> elements = new ArrayList<EclipseNode>(); if (annotations != null) for (Annotation an : annotations) addIfNotNull(elements, buildAnnotation(an, varDecl)); @@ -467,9 +523,9 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { private EclipseNode buildStatement(Statement child) { if (child == null) return null; - if (child instanceof TypeDeclaration) return buildType((TypeDeclaration)child); + if (child instanceof TypeDeclaration) return buildType((TypeDeclaration) child); - if (child instanceof LocalDeclaration) return buildLocal((LocalDeclaration)child, Kind.LOCAL); + if (child instanceof LocalDeclaration) return buildLocal((LocalDeclaration) child, Kind.LOCAL); if (setAndGetAsHandled(child)) return null; @@ -491,21 +547,35 @@ public class EclipseAST extends AST<EclipseAST, EclipseNode, ASTNode> { private static class EcjReflectionCheck { private static final String COMPILATIONRESULT_TYPE = "org.eclipse.jdt.internal.compiler.CompilationResult"; - public static Method addProblemToCompilationResult; - public static final Throwable problem; - + public static final Method addProblemToCompilationResult; + public static final Throwable problemAddProblemToCompilationResult; + public static final Method typeReferenceGetAnnotationsOnDimensions; + public static final Field typeReferenceAnnotations; static { Throwable problem_ = null; - Method m = null; + Method m1 = null, m2; + Field f; try { - m = Permit.getMethod(EclipseAstProblemView.class, "addProblemToCompilationResult", char[].class, Class.forName(COMPILATIONRESULT_TYPE), boolean.class, String.class, int.class, int.class); + m1 = Permit.getMethod(EclipseAstProblemView.class, "addProblemToCompilationResult", char[].class, Class.forName(COMPILATIONRESULT_TYPE), boolean.class, String.class, int.class, int.class); } catch (Throwable t) { // That's problematic, but as long as no local classes are used we don't actually need it. // Better fail on local classes than crash altogether. problem_ = t; } - addProblemToCompilationResult = m; - problem = problem_; + try { + m2 = Permit.getMethod(TypeReference.class, "getAnnotationsOnDimensions"); + } catch (Throwable t) { + m2 = null; + } + try { + f = Permit.getField(TypeReference.class, "annotations"); + } catch (Throwable t) { + f = null; + } + addProblemToCompilationResult = m1; + problemAddProblemToCompilationResult = problem_; + typeReferenceGetAnnotationsOnDimensions = m2; + typeReferenceAnnotations = f; } } } diff --git a/src/core/lombok/eclipse/EclipseASTAdapter.java b/src/core/lombok/eclipse/EclipseASTAdapter.java index 61807fff..c6ad059d 100644 --- a/src/core/lombok/eclipse/EclipseASTAdapter.java +++ b/src/core/lombok/eclipse/EclipseASTAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 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 @@ -30,6 +30,7 @@ import org.eclipse.jdt.internal.compiler.ast.Initializer; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; /** * Standard adapter for the {@link EclipseASTVisitor} interface. Every method on that interface @@ -97,6 +98,15 @@ public abstract class EclipseASTAdapter implements EclipseASTVisitor { public void endVisitLocal(EclipseNode localNode, LocalDeclaration local) {} /** {@inheritDoc} */ + @Override public void visitTypeUse(EclipseNode typeUseNode, TypeReference typeUse) {} + + /** {@inheritDoc} */ + public void visitAnnotationOnTypeUse(TypeReference typeUse, EclipseNode annotationNode, Annotation annotation) {} + + /** {@inheritDoc} */ + @Override public void endVisitTypeUse(EclipseNode typeUseNode, TypeReference typeUse) {} + + /** {@inheritDoc} */ public void visitStatement(EclipseNode statementNode, Statement statement) {} /** {@inheritDoc} */ diff --git a/src/core/lombok/eclipse/EclipseASTVisitor.java b/src/core/lombok/eclipse/EclipseASTVisitor.java index 37bda5e3..0bd668bc 100644 --- a/src/core/lombok/eclipse/EclipseASTVisitor.java +++ b/src/core/lombok/eclipse/EclipseASTVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 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 @@ -107,6 +107,13 @@ public interface EclipseASTVisitor { void endVisitLocal(EclipseNode localNode, LocalDeclaration local); /** + * Visits a node that represents a type reference. Anything from {@code int} to {@code T} to {@code foo,.pkg.Bar<T>.Baz<?> @Ann []}. + */ + void visitTypeUse(EclipseNode typeUseNode, TypeReference typeUse); + void visitAnnotationOnTypeUse(TypeReference typeUse, EclipseNode annotationNode, Annotation annotation); + void endVisitTypeUse(EclipseNode typeUseNode, TypeReference typeUse); + + /** * Visits a statement that isn't any of the other visit methods (e.g. TypeDeclaration). */ void visitStatement(EclipseNode statementNode, Statement statement); @@ -412,6 +419,21 @@ public interface EclipseASTVisitor { print("</LOCAL %s %s>", str(local.type), str(local.name)); } + @Override public void visitTypeUse(EclipseNode typeUseNode, TypeReference typeUse) { + print("<TYPE %s>", typeUse.getClass()); + indent++; + print("%s", typeUse); + } + + @Override public void visitAnnotationOnTypeUse(TypeReference typeUse, EclipseNode annotationNode, Annotation annotation) { + print("<ANNOTATION%s: %s />", isGenerated(annotation) ? " (GENERATED)" : "", annotation); + } + + @Override public void endVisitTypeUse(EclipseNode typeUseNode, TypeReference typeUse) { + indent--; + print("</TYPE %s>", typeUse.getClass()); + } + public void visitStatement(EclipseNode node, Statement statement) { print("<%s%s%s>", statement.getClass(), isGenerated(statement) ? " (GENERATED)" : "", position(node)); if (statement instanceof AllocationExpression) { diff --git a/src/core/lombok/eclipse/EclipseNode.java b/src/core/lombok/eclipse/EclipseNode.java index a0580c51..4c7f4eac 100644 --- a/src/core/lombok/eclipse/EclipseNode.java +++ b/src/core/lombok/eclipse/EclipseNode.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 @@ -38,6 +38,7 @@ import org.eclipse.jdt.internal.compiler.ast.Initializer; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; /** @@ -119,10 +120,18 @@ public class EclipseNode extends lombok.core.LombokNode<EclipseAST, EclipseNode, case LOCAL: visitor.visitAnnotationOnLocal((LocalDeclaration) parent.get(), this, (Annotation) get()); break; + case TYPE_USE: + visitor.visitAnnotationOnTypeUse((TypeReference) parent.get(), this, (Annotation) get()); + break; default: throw new AssertionError("Annotation not expected as child of a " + up().getKind()); } break; + case TYPE_USE: + visitor.visitTypeUse(this, (TypeReference) get()); + ast.traverseChildren(visitor, this); + visitor.endVisitTypeUse(this, (TypeReference) get()); + break; case STATEMENT: visitor.visitStatement(this, (Statement) get()); ast.traverseChildren(visitor, this); diff --git a/src/core/lombok/eclipse/TransformEclipseAST.java b/src/core/lombok/eclipse/TransformEclipseAST.java index e5edba64..6fcde937 100644 --- a/src/core/lombok/eclipse/TransformEclipseAST.java +++ b/src/core/lombok/eclipse/TransformEclipseAST.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 @@ -39,6 +39,7 @@ import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.parser.Parser; /** @@ -236,5 +237,10 @@ public class TransformEclipseAST { CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get(); nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority)); } + + @Override public void visitAnnotationOnTypeUse(TypeReference typeUse, EclipseNode annotationNode, Annotation annotation) { + CompilationUnitDeclaration top = (CompilationUnitDeclaration) annotationNode.top().get(); + nextPriority = Math.min(nextPriority, handlers.handleAnnotation(top, annotationNode, annotation, priority)); + } } } diff --git a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java index b9b9e07d..81ddbd0a 100644..100755 --- a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java +++ b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java @@ -341,7 +341,7 @@ public class EclipseSingularsRecipes { } if (arguments.isEmpty()) return null; - return arguments.toArray(new TypeReference[arguments.size()]); + return arguments.toArray(new TypeReference[0]); } private static final char[] SIZE_TEXT = new char[] {'s', 'i', 'z', 'e'}; diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index fc11aff2..3391b99d 100644..100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2018 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 @@ -87,6 +87,7 @@ import lombok.core.HandlerPriority; import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; import lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer; import lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData; import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists; @@ -460,9 +461,13 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain); } - if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) { - MethodDeclaration md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast); - if (md != null) injectMethod(builderType, md); + { + MemberExistsResult methodExists = methodExists(buildMethodName, builderType, -1); + if (methodExists == MemberExistsResult.EXISTS_BY_LOMBOK) methodExists = methodExists(buildMethodName, builderType, 0); + if (methodExists == MemberExistsResult.NOT_EXISTS) { + MethodDeclaration md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast); + if (md != null) injectMethod(builderType, md); + } } if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) { @@ -663,7 +668,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { if (staticName == null) { AllocationExpression allocationStatement = new AllocationExpression(); allocationStatement.type = copyType(out.returnType); - allocationStatement.arguments = args.isEmpty() ? null : args.toArray(new Expression[args.size()]); + allocationStatement.arguments = args.isEmpty() ? null : args.toArray(new Expression[0]); statements.add(new ReturnStatement(allocationStatement, 0, 0)); } else { MessageSend invoke = new MessageSend(); @@ -674,14 +679,14 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { invoke.receiver = new QualifiedThisReference(new SingleTypeReference(type.up().getName().toCharArray(), 0) , 0, 0); invoke.typeArguments = typeParameterNames(((TypeDeclaration) type.get()).typeParameters); - invoke.arguments = args.isEmpty() ? null : args.toArray(new Expression[args.size()]); + invoke.arguments = args.isEmpty() ? null : args.toArray(new Expression[0]); if (returnType instanceof SingleTypeReference && Arrays.equals(TypeConstants.VOID, ((SingleTypeReference) returnType).token)) { statements.add(invoke); } else { statements.add(new ReturnStatement(invoke, 0, 0)); } } - out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[statements.size()]); + out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]); out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return out; } diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index 82859e4b..660b9985 100644..100755 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -447,8 +447,8 @@ public class HandleConstructor { } nullChecks.addAll(assigns); - constructor.statements = nullChecks.isEmpty() ? null : nullChecks.toArray(new Statement[nullChecks.size()]); - constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[params.size()]); + constructor.statements = nullChecks.isEmpty() ? null : nullChecks.toArray(new Statement[0]); + constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[0]); /* Generate annotations that must be put on the generated method, and attach them. */ { Annotation[] constructorProperties = null; @@ -550,8 +550,8 @@ public class HandleConstructor { params.add(parameter); } - statement.arguments = assigns.isEmpty() ? null : assigns.toArray(new Expression[assigns.size()]); - constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[params.size()]); + statement.arguments = assigns.isEmpty() ? null : assigns.toArray(new Expression[0]); + constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[0]); constructor.statements = new Statement[] { new ReturnStatement(statement, (int) (p >> 32), (int)p) }; constructor.traverse(new SetGeneratedByVisitor(source), typeDecl.scope); diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index 84e5185d..046b197f 100644..100755 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -391,7 +391,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH setGeneratedBy(returnStatement, source); statements.add(returnStatement); } - method.statements = statements.toArray(new Statement[statements.size()]); + method.statements = statements.toArray(new Statement[0]); return method; } @@ -738,7 +738,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH setGeneratedBy(returnStatement, source); statements.add(returnStatement); } - method.statements = statements.toArray(new Statement[statements.size()]); + method.statements = statements.toArray(new Statement[0]); return method; } diff --git a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java index 9e81a068..1caccd59 100644 --- a/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java +++ b/src/core/lombok/eclipse/handlers/HandleFieldNameConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2018 The Project Lombok Authors. + * Copyright (C) 2014-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 @@ -27,15 +27,7 @@ import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.util.ArrayList; import java.util.List; -import lombok.AccessLevel; -import lombok.ConfigurationKeys; -import lombok.core.AST.Kind; -import lombok.core.AnnotationValues; -import lombok.eclipse.Eclipse; -import lombok.eclipse.EclipseAnnotationHandler; -import lombok.eclipse.EclipseNode; -import lombok.experimental.FieldNameConstants; - +import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Annotation; @@ -51,6 +43,16 @@ import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.mangosdk.spi.ProviderFor; +import lombok.AccessLevel; +import lombok.ConfigurationKeys; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.eclipse.Eclipse; +import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; +import lombok.experimental.FieldNameConstants; + @ProviderFor(EclipseAnnotationHandler.class) public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldNameConstants> { public void generateFieldNameConstantsForType(EclipseNode typeNode, EclipseNode errorNode, AccessLevel level, boolean asEnum, String innerTypeName, boolean onlyExplicit) { @@ -88,7 +90,7 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldName return filterField(fieldDecl); } - public void handle(AnnotationValues<FieldNameConstants> annotation, Annotation ast, EclipseNode annotationNode) { + @Override public void handle(AnnotationValues<FieldNameConstants> annotation, Annotation ast, EclipseNode annotationNode) { handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.FIELD_NAME_CONSTANTS_FLAG_USAGE, "@FieldNameConstants"); EclipseNode node = annotationNode.up(); @@ -117,6 +119,7 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldName private void createInnerTypeFieldNameConstants(EclipseNode typeNode, EclipseNode errorNode, ASTNode source, AccessLevel level, List<EclipseNode> fields, boolean asEnum, String innerTypeName) { if (fields.isEmpty()) return; + ASTVisitor generatedByVisitor = new SetGeneratedByVisitor(source); TypeDeclaration parent = (TypeDeclaration) typeNode.get(); EclipseNode fieldsType = findInnerClass(typeNode, innerTypeName); boolean genConstr = false, genClinit = false; @@ -125,11 +128,12 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldName if (fieldsType == null) { generatedInnerType = new TypeDeclaration(parent.compilationResult); generatedInnerType.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; - generatedInnerType.modifiers = toEclipseModifier(level) | (asEnum ? ClassFileConstants.AccEnum : ClassFileConstants.AccStatic | ClassFileConstants.AccFinal); + generatedInnerType.modifiers = toEclipseModifier(level) | (asEnum ? ClassFileConstants.AccEnum : (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal)); generatedInnerType.name = name; fieldsType = injectType(typeNode, generatedInnerType); genConstr = true; genClinit = asEnum; + generatedInnerType.traverse(generatedByVisitor, ((TypeDeclaration) typeNode.get()).scope); } else { TypeDeclaration builderTypeDeclaration = (TypeDeclaration) fieldsType.get(); if (asEnum && (builderTypeDeclaration.modifiers & ClassFileConstants.AccEnum) == 0) { @@ -146,8 +150,6 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldName if (genConstr) { ConstructorDeclaration constructor = new ConstructorDeclaration(parent.compilationResult); constructor.selector = name; - constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart; - constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd; constructor.modifiers = ClassFileConstants.AccPrivate; ExplicitConstructorCall superCall = new ExplicitConstructorCall(0); superCall.sourceStart = source.sourceStart; @@ -157,11 +159,12 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldName if (!asEnum) constructor.statements = new Statement[0]; injectMethod(fieldsType, constructor); } + if (genClinit) { Clinit cli = new Clinit(parent.compilationResult); injectMethod(fieldsType, cli); + cli.traverse(generatedByVisitor, ((TypeDeclaration) fieldsType.get()).scope); } - for (EclipseNode fieldNode : fields) { FieldDeclaration field = (FieldDeclaration) fieldNode.get(); @@ -171,19 +174,20 @@ public class HandleFieldNameConstants extends EclipseAnnotationHandler<FieldName long p = (long) pS << 32 | pE; FieldDeclaration constantField = new FieldDeclaration(fName, pS, pE); constantField.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; - constantField.modifiers = asEnum ? 0 : ClassFileConstants.AccPublic | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal; - constantField.type = asEnum ? null : new QualifiedTypeReference(TypeConstants.JAVA_LANG_STRING, new long[] {p, p, p}); if (asEnum) { AllocationExpression ac = new AllocationExpression(); ac.enumConstant = constantField; ac.sourceStart = source.sourceStart; ac.sourceEnd = source.sourceEnd; constantField.initialization = ac; + constantField.modifiers = 0; } else { + constantField.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_STRING, new long[] {p, p, p}); constantField.initialization = new StringLiteral(field.name, pS, pE, 0); + constantField.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal; } - constantField.traverse(new SetGeneratedByVisitor(source), null); injectField(fieldsType, constantField); + constantField.traverse(generatedByVisitor, ((TypeDeclaration) fieldsType.get()).initializerScope); } } } diff --git a/src/core/lombok/eclipse/handlers/HandleHelper.java b/src/core/lombok/eclipse/handlers/HandleHelper.java index 4f06bdfd..36f53813 100644..100755 --- a/src/core/lombok/eclipse/handlers/HandleHelper.java +++ b/src/core/lombok/eclipse/handlers/HandleHelper.java @@ -103,7 +103,7 @@ public class HandleHelper extends EclipseAnnotationHandler<Helper> { } Collections.sort(knownMethodNames); - final String[] knownMethodNames_ = knownMethodNames.toArray(new String[knownMethodNames.size()]); + final String[] knownMethodNames_ = knownMethodNames.toArray(new String[0]); final char[] helperName = new char[annotatedType_.name.length + 1]; final boolean[] helperUsed = new boolean[1]; diff --git a/src/core/lombok/eclipse/handlers/HandleNonNull.java b/src/core/lombok/eclipse/handlers/HandleNonNull.java index ebc62909..1672618d 100644 --- a/src/core/lombok/eclipse/handlers/HandleNonNull.java +++ b/src/core/lombok/eclipse/handlers/HandleNonNull.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 @@ -33,6 +33,7 @@ import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.eclipse.DeferUntilPostDiet; +import lombok.eclipse.EclipseAST; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; @@ -52,6 +53,7 @@ import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement; import org.eclipse.jdt.internal.compiler.ast.ThrowStatement; import org.eclipse.jdt.internal.compiler.ast.TryStatement; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.mangosdk.spi.ProviderFor; @DeferUntilPostDiet @@ -95,14 +97,33 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { return; } - if (annotationNode.up().getKind() != Kind.ARGUMENT) return; - - Argument arg; + Argument param; + EclipseNode paramNode; AbstractMethodDeclaration declaration; + switch (annotationNode.up().getKind()) { + case ARGUMENT: + paramNode = annotationNode.up(); + break; + case TYPE_USE: + EclipseNode typeNode = annotationNode.directUp(); + boolean ok = false; + ASTNode astNode = typeNode.get(); + if (astNode instanceof TypeReference) { + Annotation[] anns = EclipseAST.getTopLevelTypeReferenceAnnotations((TypeReference) astNode); + if (anns == null) return; + for (Annotation ann : anns) if (ast == ann) ok = true; + } + if (!ok) return; + paramNode = typeNode.directUp(); + break; + default: + return; + } + try { - arg = (Argument) annotationNode.up().get(); - declaration = (AbstractMethodDeclaration) annotationNode.up().up().get(); + param = (Argument) paramNode.get(); + declaration = (AbstractMethodDeclaration) paramNode.up().get(); } catch (Exception e) { return; } @@ -118,7 +139,7 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { // and if they exist, create a new method in the class: 'private static <T> T lombok$nullCheck(T expr, String msg) {if (expr == null) throw NPE; return expr;}' and // wrap all references to it in the super/this to a call to this method. - Statement nullCheck = generateNullCheck(arg, annotationNode); + Statement nullCheck = generateNullCheck(param, annotationNode); if (nullCheck == null) { // @NonNull applied to a primitive. Kinda pointless. Let's generate a warning. @@ -129,7 +150,7 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { if (declaration.statements == null) { declaration.statements = new Statement[] {nullCheck}; } else { - char[] expectedName = arg.name; + char[] expectedName = param.name; /* Abort if the null check is already there, delving into try and synchronized statements */ { Statement[] stats = declaration.statements; int idx = 0; @@ -162,7 +183,7 @@ public class HandleNonNull extends EclipseAnnotationHandler<NonNull> { newStatements[skipOver] = nullCheck; declaration.statements = newStatements; } - annotationNode.up().up().rebuild(); + paramNode.up().rebuild(); } public boolean isNullCheck(Statement stat) { diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 9a3275c2..7b6a3c28 100644..100755 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -546,7 +546,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } } - constructor.statements = statements.isEmpty() ? null : statements.toArray(new Statement[statements.size()]); + constructor.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]); constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope); @@ -654,7 +654,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { returnCall.selector = SELF_METHOD_NAME; body.add(new ReturnStatement(returnCall, 0, 0)); - out.statements = body.isEmpty() ? null : body.toArray(new Statement[body.size()]); + out.statements = body.isEmpty() ? null : body.toArray(new Statement[0]); return out; } @@ -694,7 +694,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { body.add(exec); } - out.statements = body.isEmpty() ? null : body.toArray(new Statement[body.size()]); + out.statements = body.isEmpty() ? null : body.toArray(new Statement[0]); return out; } @@ -788,7 +788,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { // Use a constructor that only has this builder as parameter. allocationStatement.arguments = new Expression[] {new ThisReference(0, 0)}; statements.add(new ReturnStatement(allocationStatement, 0, 0)); - out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[statements.size()]); + out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]); out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return out; } diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java index 4b094a9f..40f01ee4 100644..100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java @@ -149,7 +149,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { thisDotFieldDotAdd.selector = getAddMethodName().toCharArray(); statements.add(thisDotFieldDotAdd); if (returnStatement != null) statements.add(returnStatement); - md.statements = statements.toArray(new Statement[statements.size()]); + md.statements = statements.toArray(new Statement[0]); md.arguments = new Argument[suffixes.size()]; for (int i = 0; i < suffixes.size(); i++) { TypeReference tr = cloneParamType(i, data.getTypeArgs(), builderType); @@ -183,7 +183,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { statements.add(thisDotFieldDotAddAll); if (returnStatement != null) statements.add(returnStatement); - md.statements = statements.toArray(new Statement[statements.size()]); + md.statements = statements.toArray(new Statement[0]); TypeReference paramType; paramType = new QualifiedTypeReference(fromQualifiedName(getAddAllTypeName()), NULL_POSS); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java index 11314bd3..32b1f71f 100644..100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java @@ -140,7 +140,7 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula statements.add(thisDotFieldDotAdd); if (returnStatement != null) statements.add(returnStatement); - md.statements = statements.toArray(new Statement[statements.size()]); + md.statements = statements.toArray(new Statement[0]); TypeReference paramType = cloneParamType(0, data.getTypeArgs(), builderType); Annotation[] typeUseAnns = getTypeUseAnnotations(paramType); removeTypeUseAnnotations(paramType); @@ -172,7 +172,7 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula statements.add(thisDotFieldDotAddAll); if (returnStatement != null) statements.add(returnStatement); - md.statements = statements.toArray(new Statement[statements.size()]); + md.statements = statements.toArray(new Statement[0]); TypeReference paramType = new QualifiedTypeReference(TypeConstants.JAVA_UTIL_COLLECTION, NULL_POSS); paramType = addTypeArgs(1, true, builderType, paramType, data.getTypeArgs()); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSingularizer.java index f512bacf..80d49fe7 100644..100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSingularizer.java @@ -115,7 +115,7 @@ public class EclipseJavaUtilListSingularizer extends EclipseJavaUtilListSetSingu } SwitchStatement switchStat = new SwitchStatement(); - switchStat.statements = switchContents.toArray(new Statement[switchContents.size()]); + switchStat.statements = switchContents.toArray(new Statement[0]); switchStat.expression = getSize(builderType, data.getPluralName(), true, builderVariable); TypeReference localShadowerType = new QualifiedTypeReference(Eclipse.fromQualifiedName(data.getTargetFqn()), NULL_POSS); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java index 55f6cadd..b24bf97f 100644..100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java @@ -215,7 +215,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer } if (returnStatement != null) statements.add(returnStatement); - md.statements = statements.toArray(new Statement[statements.size()]); + md.statements = statements.toArray(new Statement[0]); TypeReference keyParamType = cloneParamType(0, data.getTypeArgs(), builderType); TypeReference valueParamType = cloneParamType(1, data.getTypeArgs(), builderType); Annotation[] typeUseAnnsKey = getTypeUseAnnotations(keyParamType); @@ -286,7 +286,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer statements.add(forEach); if (returnStatement != null) statements.add(returnStatement); - md.statements = statements.toArray(new Statement[statements.size()]); + md.statements = statements.toArray(new Statement[0]); TypeReference paramType = new QualifiedTypeReference(JAVA_UTIL_MAP, NULL_POSS); paramType = addTypeArgs(2, true, builderType, paramType, data.getTypeArgs()); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java index 8bcfa65d..8aeffc48 100644..100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilSingularizer.java @@ -147,7 +147,7 @@ abstract class EclipseJavaUtilSingularizer extends EclipseSingularizer { } SwitchStatement switchStat = new SwitchStatement(); - switchStat.statements = switchContents.toArray(new Statement[switchContents.size()]); + switchStat.statements = switchContents.toArray(new Statement[0]); switchStat.expression = getSize(builderType, keyName, true, builderVariable); TypeReference localShadowerType = new QualifiedTypeReference(fromQualifiedName(data.getTargetFqn()), NULL_POSS); diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index f2901038..f6cd5571 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -47,15 +47,19 @@ import com.sun.tools.javac.model.JavacElements; import com.sun.tools.javac.model.JavacTypes; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree; import com.sun.tools.javac.tree.JCTree.JCBlock; 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.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCTry; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.JCTree.JCWildcard; import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; @@ -192,6 +196,8 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { return buildStatementOrExpression(node); case ANNOTATION: return buildAnnotation((JCAnnotation) node, false); + case TYPE_USE: + return buildTypeUse(node); default: throw new AssertionError("Did not expect: " + kind); } @@ -233,6 +239,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { if (setAndGetAsHandled(field)) return null; List<JavacNode> childNodes = new ArrayList<JavacNode>(); for (JCAnnotation annotation : field.mods.annotations) addIfNotNull(childNodes, buildAnnotation(annotation, true)); + addIfNotNull(childNodes, buildTypeUse(field.vartype)); addIfNotNull(childNodes, buildExpression(field.init)); return putInMap(new JavacNode(this, field, childNodes, Kind.FIELD)); } @@ -241,23 +248,62 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { if (setAndGetAsHandled(local)) return null; List<JavacNode> childNodes = new ArrayList<JavacNode>(); for (JCAnnotation annotation : local.mods.annotations) addIfNotNull(childNodes, buildAnnotation(annotation, true)); + addIfNotNull(childNodes, buildTypeUse(local.vartype)); addIfNotNull(childNodes, buildExpression(local.init)); return putInMap(new JavacNode(this, local, childNodes, kind)); } - private static boolean JCTRY_RESOURCES_FIELD_INITIALIZED; + private JavacNode buildTypeUse(JCTree typeUse) { + if (setAndGetAsHandled(typeUse)) return null; + + if (typeUse == null) return null; + + if (typeUse.getClass().getSimpleName().equals("JCAnnotatedType")) { + initJcAnnotatedType(typeUse.getClass()); + Collection<?> anns = Permit.permissiveReadField(Collection.class, JCANNOTATEDTYPE_ANNOTATIONS, typeUse); + JCExpression underlying = Permit.permissiveReadField(JCExpression.class, JCANNOTATEDTYPE_UNDERLYINGTYPE, typeUse); + + List<JavacNode> childNodes = new ArrayList<JavacNode>(); + if (anns != null) for (Object annotation : anns) if (annotation instanceof JCAnnotation) addIfNotNull(childNodes, buildAnnotation((JCAnnotation) annotation, true)); + addIfNotNull(childNodes, buildTypeUse(underlying)); + return putInMap(new JavacNode(this, typeUse, childNodes, Kind.TYPE_USE)); + } + + if (typeUse instanceof JCWildcard) { + JCTree inner = ((JCWildcard) typeUse).inner; + List<JavacNode> childNodes = inner == null ? Collections.<JavacNode>emptyList() : new ArrayList<JavacNode>(); + if (inner != null) addIfNotNull(childNodes, buildTypeUse(inner)); + return putInMap(new JavacNode(this, typeUse, childNodes, Kind.TYPE_USE)); + } + + if (typeUse instanceof JCArrayTypeTree) { + JCTree inner = ((JCArrayTypeTree) typeUse).elemtype; + List<JavacNode> childNodes = inner == null ? Collections.<JavacNode>emptyList() : new ArrayList<JavacNode>(); + if (inner != null) addIfNotNull(childNodes, buildTypeUse(inner)); + return putInMap(new JavacNode(this, typeUse, childNodes, Kind.TYPE_USE)); + } + + if (typeUse instanceof JCFieldAccess) { + JCTree inner = ((JCFieldAccess) typeUse).selected; + List<JavacNode> childNodes = inner == null ? Collections.<JavacNode>emptyList() : new ArrayList<JavacNode>(); + if (inner != null) addIfNotNull(childNodes, buildTypeUse(inner)); + return putInMap(new JavacNode(this, typeUse, childNodes, Kind.TYPE_USE)); + } + + if (typeUse instanceof JCIdent) { + return putInMap(new JavacNode(this, typeUse, Collections.<JavacNode>emptyList(), Kind.TYPE_USE)); + } + + return null; + } + + private static boolean JCTRY_RESOURCES_FIELD_INITIALIZED = false; private static Field JCTRY_RESOURCES_FIELD; @SuppressWarnings("unchecked") private static List<JCTree> getResourcesForTryNode(JCTry tryNode) { if (!JCTRY_RESOURCES_FIELD_INITIALIZED) { - try { - JCTRY_RESOURCES_FIELD = Permit.getField(JCTry.class, "resources"); - } catch (NoSuchFieldException ignore) { - // Java 1.6 or lower won't have this at all. - } catch (Exception ignore) { - // Shouldn't happen. Best thing we can do is just carry on and break on try/catch. - } + JCTRY_RESOURCES_FIELD = Permit.permissiveGetField(JCTry.class, "resources"); JCTRY_RESOURCES_FIELD_INITIALIZED = true; } @@ -271,6 +317,15 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { return Collections.emptyList(); } + private static boolean JCANNOTATEDTYPE_FIELDS_INITIALIZED = false; + private static Field JCANNOTATEDTYPE_ANNOTATIONS, JCANNOTATEDTYPE_UNDERLYINGTYPE; + private static void initJcAnnotatedType(Class<?> context) { + if (JCANNOTATEDTYPE_FIELDS_INITIALIZED) return; + JCANNOTATEDTYPE_ANNOTATIONS = Permit.permissiveGetField(context, "annotations"); + JCANNOTATEDTYPE_UNDERLYINGTYPE = Permit.permissiveGetField(context, "underlyingType"); + JCANNOTATEDTYPE_FIELDS_INITIALIZED = true; + } + private JavacNode buildTry(JCTry tryNode) { if (setAndGetAsHandled(tryNode)) return null; List<JavacNode> childNodes = new ArrayList<JavacNode>(); @@ -323,8 +378,8 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { private JavacNode buildStatementOrExpression(JCTree statement) { if (statement == null) return null; if (statement instanceof JCAnnotation) return null; - if (statement instanceof JCClassDecl) return buildType((JCClassDecl)statement); - if (statement instanceof JCVariableDecl) return buildLocalVar((JCVariableDecl)statement, Kind.LOCAL); + if (statement instanceof JCClassDecl) return buildType((JCClassDecl) statement); + if (statement instanceof JCVariableDecl) return buildLocalVar((JCVariableDecl) statement, Kind.LOCAL); if (statement instanceof JCTry) return buildTry((JCTry) statement); if (statement.getClass().getSimpleName().equals("JCLambda")) return buildLambda(statement); if (setAndGetAsHandled(statement)) return null; diff --git a/src/core/lombok/javac/JavacASTAdapter.java b/src/core/lombok/javac/JavacASTAdapter.java index 6af53e3d..4c1912d8 100644 --- a/src/core/lombok/javac/JavacASTAdapter.java +++ b/src/core/lombok/javac/JavacASTAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 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 @@ -96,6 +96,15 @@ public class JavacASTAdapter implements JavacASTVisitor { @Override public void endVisitLocal(JavacNode localNode, JCVariableDecl local) {} /** {@inheritDoc} */ + @Override public void visitTypeUse(JavacNode typeUseNode, JCTree typeUse) {} + + /** {@inheritDoc} */ + @Override public void visitAnnotationOnTypeUse(JCTree typeUse, JavacNode annotationNode, JCAnnotation annotation) {} + + /** {@inheritDoc} */ + @Override public void endVisitTypeUse(JavacNode typeUseNode, JCTree typeUse) {} + + /** {@inheritDoc} */ @Override public void visitStatement(JavacNode statementNode, JCTree statement) {} /** {@inheritDoc} */ diff --git a/src/core/lombok/javac/JavacASTVisitor.java b/src/core/lombok/javac/JavacASTVisitor.java index d4f8f731..9b67dda3 100644 --- a/src/core/lombok/javac/JavacASTVisitor.java +++ b/src/core/lombok/javac/JavacASTVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 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 @@ -89,6 +89,13 @@ public interface JavacASTVisitor { void endVisitLocal(JavacNode localNode, JCVariableDecl local); /** + * Visits a node that represents a type reference. Anything from {@code int} to {@code T} to {@code foo.pkg.Bar<T>.Baz<?> @Ann []}. + */ + void visitTypeUse(JavacNode typeUseNode, JCTree typeUse); + void visitAnnotationOnTypeUse(JCTree typeUse, JavacNode annotationNode, JCAnnotation annotation); + void endVisitTypeUse(JavacNode typeUseNode, JCTree typeUse); + + /** * Visits a statement that isn't any of the other visit methods (e.g. JCClassDecl). * The statement object is guaranteed to be either a JCStatement or a JCExpression. */ @@ -261,6 +268,21 @@ public interface JavacASTVisitor { print("</LOCAL %s %s>", local.vartype, local.name); } + @Override public void visitTypeUse(JavacNode node, JCTree typeUse) { + print("<TYPE %s>", typeUse.getClass()); + indent++; + print("%s", typeUse); + } + + @Override public void visitAnnotationOnTypeUse(JCTree typeUse, JavacNode node, JCAnnotation annotation) { + print("<ANNOTATION: %s />", annotation); + } + + @Override public void endVisitTypeUse(JavacNode node, JCTree typeUse) { + indent--; + print("</TYPE %s>", typeUse.getClass()); + } + @Override public void visitStatement(JavacNode node, JCTree statement) { print("<%s>", statement.getClass()); indent++; diff --git a/src/core/lombok/javac/JavacNode.java b/src/core/lombok/javac/JavacNode.java index f119f1f9..191ab3c0 100644 --- a/src/core/lombok/javac/JavacNode.java +++ b/src/core/lombok/javac/JavacNode.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 @@ -145,10 +145,18 @@ public class JavacNode extends lombok.core.LombokNode<JavacAST, JavacNode, JCTre case LOCAL: visitor.visitAnnotationOnLocal((JCVariableDecl) up().get(), this, (JCAnnotation) get()); break; + case TYPE_USE: + visitor.visitAnnotationOnTypeUse(up().get(), this, (JCAnnotation) get()); + break; default: throw new AssertionError("Annotion not expected as child of a " + up().getKind()); } break; + case TYPE_USE: + visitor.visitTypeUse(this, get()); + ast.traverseChildren(visitor, this); + visitor.endVisitTypeUse(this, get()); + break; default: throw new AssertionError("Unexpected kind during node traversal: " + getKind()); } diff --git a/src/core/lombok/javac/JavacTransformer.java b/src/core/lombok/javac/JavacTransformer.java index 0a4f1f73..625fb283 100644 --- a/src/core/lombok/javac/JavacTransformer.java +++ b/src/core/lombok/javac/JavacTransformer.java @@ -27,6 +27,7 @@ import java.util.SortedSet; import javax.annotation.processing.Messager; import com.sun.source.util.Trees; +import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; @@ -114,5 +115,10 @@ public class JavacTransformer { JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); handlers.handleAnnotation(top, annotationNode, annotation, priority); } + + @Override public void visitAnnotationOnTypeUse(JCTree typeUse, JavacNode annotationNode, JCAnnotation annotation) { + JCCompilationUnit top = (JCCompilationUnit) annotationNode.top().get(); + handlers.handleAnnotation(top, annotationNode, annotation, priority); + } } } diff --git a/src/core/lombok/javac/apt/EmptyLombokFileObject.java b/src/core/lombok/javac/apt/EmptyLombokFileObject.java deleted file mode 100644 index d1d00582..00000000 --- a/src/core/lombok/javac/apt/EmptyLombokFileObject.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2010-2018 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.apt; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.StringReader; -import java.io.Writer; -import java.net.URI; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CodingErrorAction; - -import javax.lang.model.element.Modifier; -import javax.lang.model.element.NestingKind; - -// Can't use SimpleJavaFileObject so we copy/paste most of its content here, because javac doesn't follow the interface, -// and casts to its own BaseFileObject type. D'oh! -class EmptyLombokFileObject implements LombokFileObject { - private final String name; - private final Kind kind; - - public EmptyLombokFileObject(String name, Kind kind) { - this.name = name; - this.kind = kind; - } - - @Override public boolean isNameCompatible(String simpleName, Kind kind) { - String baseName = simpleName + kind.extension; - return kind.equals(getKind()) - && (baseName.equals(toUri().getPath()) || toUri().getPath().endsWith("/" + baseName)); - } - - @Override public URI toUri() { - return URI.create("file:///" + (name.startsWith("/") ? name.substring(1) : name)); - } - - @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { - return ""; - } - - @Override public InputStream openInputStream() throws IOException { - return new ByteArrayInputStream(new byte[0]); - } - - @Override public Reader openReader(boolean ignoreEncodingErrors) throws IOException { - return new StringReader(""); - } - - @Override public Writer openWriter() throws IOException { - return new OutputStreamWriter(openOutputStream()); - } - - @Override public OutputStream openOutputStream() throws IOException { - return new ByteArrayOutputStream(); - } - - @Override public long getLastModified() { - return 0L; - } - - @Override public boolean delete() { - return false; - } - - @Override public Kind getKind() { - return kind; - } - - @SuppressWarnings("all") - @Override public String getName() { - return toUri().getPath(); - } - - @Override public NestingKind getNestingKind() { - return null; - } - - @Override public Modifier getAccessLevel() { - return null; - } - - @Override public CharsetDecoder getDecoder(boolean ignoreEncodingErrors) { - CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder(); - CodingErrorAction action = ignoreEncodingErrors ? CodingErrorAction.REPLACE : CodingErrorAction.REPORT; - return decoder.onMalformedInput(action).onUnmappableCharacter(action); - } - - @Override public boolean equals(Object obj) { - if (!(obj instanceof EmptyLombokFileObject)) return false; - if (obj == this) return true; - EmptyLombokFileObject other = (EmptyLombokFileObject) obj; - return name.equals(other.name) && kind.equals(other.kind); - } - - @Override public int hashCode() { - return name.hashCode() ^ kind.hashCode(); - } -}
\ No newline at end of file diff --git a/src/core/lombok/javac/apt/InterceptingJavaFileManager.java b/src/core/lombok/javac/apt/InterceptingJavaFileManager.java index 9b58d111..3f4c6ef1 100644 --- a/src/core/lombok/javac/apt/InterceptingJavaFileManager.java +++ b/src/core/lombok/javac/apt/InterceptingJavaFileManager.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 @@ -42,11 +42,6 @@ final class InterceptingJavaFileManager extends ForwardingJavaFileManager<JavaFi } @Override public JavaFileObject getJavaFileForOutput(Location location, String className, final Kind kind, FileObject sibling) throws IOException { - if (className.contains("lombok.dummy.ForceNewRound")) { - final String name = className.replace(".", "/") + kind.extension; - return LombokFileObjects.createEmpty(compiler, name, kind); - } - JavaFileObject fileObject = fileManager.getJavaFileForOutput(location, className, kind, sibling); if (kind != Kind.CLASS) return fileObject; diff --git a/src/core/lombok/javac/apt/LombokFileObjects.java b/src/core/lombok/javac/apt/LombokFileObjects.java index d6c96480..f6643db3 100644 --- a/src/core/lombok/javac/apt/LombokFileObjects.java +++ b/src/core/lombok/javac/apt/LombokFileObjects.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 @@ -38,11 +38,11 @@ import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; +import com.sun.tools.javac.file.BaseFileManager; + import lombok.core.DiagnosticsReceiver; import lombok.permit.Permit; -import com.sun.tools.javac.file.BaseFileManager; - //Can't use SimpleJavaFileObject so we copy/paste most of its content here, because javac doesn't follow the interface, //and casts to its own BaseFileObject type. D'oh! final class LombokFileObjects { @@ -152,10 +152,6 @@ final class LombokFileObjects { throw new IllegalArgumentException(sb.toString()); } - static JavaFileObject createEmpty(Compiler compiler, String name, Kind kind) { - return compiler.wrap(new EmptyLombokFileObject(name, kind)); - } - static JavaFileObject createIntercepting(Compiler compiler, JavaFileObject delegate, String fileName, DiagnosticsReceiver diagnostics) { return compiler.wrap(new InterceptingJavaFileObject(delegate, fileName, diagnostics, compiler.getDecoderMethod())); } diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index d4f3504a..79db5dec 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -23,7 +23,6 @@ package lombok.javac.apt; import java.io.IOException; import java.io.InputStream; -import java.io.Writer; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; @@ -47,13 +46,6 @@ import javax.lang.model.element.QualifiedNameable; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic.Kind; import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; - -import lombok.Lombok; -import lombok.core.CleanupRegistry; -import lombok.core.DiagnosticsReceiver; -import lombok.javac.JavacTransformer; -import lombok.permit.Permit; import com.sun.source.util.TreePath; import com.sun.source.util.Trees; @@ -64,6 +56,12 @@ import com.sun.tools.javac.processing.JavacProcessingEnvironment; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.util.Context; +import lombok.Lombok; +import lombok.core.CleanupRegistry; +import lombok.core.DiagnosticsReceiver; +import lombok.javac.JavacTransformer; +import lombok.permit.Permit; + /** * This Annotation Processor is the standard injection mechanism for lombok-enabling the javac compiler. * @@ -362,11 +360,7 @@ public class LombokProcessor extends AbstractProcessor { private void forceNewRound(String randomModuleName, JavacFiler filer) { if (!filer.newFiles()) { try { - String name = "lombok.dummy.ForceNewRound" + (dummyCount++); - if (randomModuleName != null) name = randomModuleName + "/" + name; - JavaFileObject dummy = filer.createSourceFile(name); - Writer w = dummy.openWriter(); - w.close(); + filer.getGeneratedSourceNames().add("lombok.dummy.ForceNewRound" + (dummyCount++)); } catch (Exception e) { e.printStackTrace(); processingEnv.getMessager().printMessage(Kind.WARNING, diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 1038f116..609adbd6 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2018 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 @@ -405,11 +405,15 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain); } - if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfBuilderMethod, returnType, builderFields, builderType, thrownExceptions, ast, addCleaning); - if (md != null) { - injectMethod(builderType, md); - recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); + { + MemberExistsResult methodExists = methodExists(builderMethodName, builderType, -1); + if (methodExists == MemberExistsResult.EXISTS_BY_LOMBOK) methodExists = methodExists(buildMethodName, builderType, 0); + if (methodExists == MemberExistsResult.NOT_EXISTS) { + JCMethodDecl md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfBuilderMethod, returnType, builderFields, builderType, thrownExceptions, ast, addCleaning); + if (md != null) { + injectMethod(builderType, md); + recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); + } } } @@ -701,13 +705,13 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { public void makeSetterMethodsForBuilder(JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, boolean fluent, boolean chain) { boolean deprecate = isFieldDeprecated(fieldNode.originalFieldNode); if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) { - makeSimpleSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.nameOfSetFlag, source, fluent, chain, fieldNode.annotations); + makeSimpleSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.nameOfSetFlag, source, fluent, chain, fieldNode.annotations, fieldNode.originalFieldNode); } else { fieldNode.singularData.getSingularizer().generateMethods(fieldNode.singularData, deprecate, builderType, source.get(), fluent, chain); } } - private void makeSimpleSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, List<JCAnnotation> annosOnParam) { + private void makeSimpleSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, List<JCAnnotation> annosOnParam, JavacNode originalFieldNode) { Name fieldName = ((JCVariableDecl) fieldNode.get()).name; for (JavacNode child : builderType.down()) { @@ -723,6 +727,8 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { JCMethodDecl newMethod = HandleSetter.createSetter(Flags.PUBLIC, deprecate, fieldNode, maker, setterName, nameOfSetFlag, chain, source, List.<JCAnnotation>nil(), annosOnParam); recursiveSetGeneratedBy(newMethod, source.get(), builderType.getContext()); + copyJavadoc(originalFieldNode, newMethod, CopyJavadoc.SETTER); + injectMethod(builderType, newMethod); } diff --git a/src/core/lombok/javac/handlers/HandleHelper.java b/src/core/lombok/javac/handlers/HandleHelper.java index 09ace4d6..6f4361c1 100644..100755 --- a/src/core/lombok/javac/handlers/HandleHelper.java +++ b/src/core/lombok/javac/handlers/HandleHelper.java @@ -102,7 +102,7 @@ public class HandleHelper extends JavacAnnotationHandler<Helper> { } Collections.sort(knownMethodNames); - final String[] knownMethodNames_ = knownMethodNames.toArray(new String[knownMethodNames.size()]); + final String[] knownMethodNames_ = knownMethodNames.toArray(new String[0]); final Name helperName = annotationNode.toName("$" + annotatedType_.name); final boolean[] helperUsed = new boolean[1]; diff --git a/src/core/lombok/javac/handlers/HandleNonNull.java b/src/core/lombok/javac/handlers/HandleNonNull.java index 81aa1525..9a81ffff 100644 --- a/src/core/lombok/javac/handlers/HandleNonNull.java +++ b/src/core/lombok/javac/handlers/HandleNonNull.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 @@ -74,12 +74,24 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> { return; } - if (annotationNode.up().getKind() != Kind.ARGUMENT) return; - JCMethodDecl declaration; + JavacNode paramNode; + + switch (annotationNode.up().getKind()) { + case ARGUMENT: + paramNode = annotationNode.up(); + break; + case TYPE_USE: + JavacNode typeNode = annotationNode.directUp(); + paramNode = typeNode.directUp(); + break; + default: + return; + } + if (paramNode.getKind() != Kind.ARGUMENT) return; try { - declaration = (JCMethodDecl) annotationNode.up().up().get(); + declaration = (JCMethodDecl) paramNode.up().get(); } catch (Exception e) { return; } @@ -93,7 +105,7 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> { // and if they exist, create a new method in the class: 'private static <T> T lombok$nullCheck(T expr, String msg) {if (expr == null) throw NPE; return expr;}' and // wrap all references to it in the super/this to a call to this method. - JCStatement nullCheck = recursiveSetGeneratedBy(generateNullCheck(annotationNode.getTreeMaker(), annotationNode.up(), annotationNode), ast, annotationNode.getContext()); + JCStatement nullCheck = recursiveSetGeneratedBy(generateNullCheck(annotationNode.getTreeMaker(), paramNode, annotationNode), ast, annotationNode.getContext()); if (nullCheck == null) { // @NonNull applied to a primitive. Kinda pointless. Let's generate a warning. @@ -103,7 +115,7 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> { List<JCStatement> statements = declaration.body.stats; - String expectedName = annotationNode.up().getName(); + String expectedName = paramNode.getName(); /* Abort if the null check is already there, delving into try and synchronized statements */ { List<JCStatement> stats = statements; diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 5fd17388..f08098d2 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -1462,7 +1462,7 @@ public class JavacHandlerUtil { * variable name as message. */ public static JCStatement generateNullCheck(JavacTreeMaker maker, JavacNode variable, JavacNode source) { - return generateNullCheck(maker, variable, (JCVariableDecl)variable.get(), source); + return generateNullCheck(maker, variable, (JCVariableDecl) variable.get(), source); } /** diff --git a/src/delombok/lombok/delombok/Delombok.java b/src/delombok/lombok/delombok/Delombok.java index 69898668..9582c3b8 100644..100755 --- a/src/delombok/lombok/delombok/Delombok.java +++ b/src/delombok/lombok/delombok/Delombok.java @@ -426,7 +426,7 @@ public class Delombok { throw new IOException("Unclosed ' in @ file"); } - return x.toArray(new String[x.size()]); + return x.toArray(new String[0]); } public static class InvalidFormatOptionException extends Exception { diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index 3fb1f1b1..84c342f0 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Project Lombok Authors. + * Copyright (C) 2016-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 @@ -258,6 +258,7 @@ public class PrettyPrinter extends JCTree.Visitor { JCMethodInvocation inv = (JCMethodInvocation) expr; if (!inv.typeargs.isEmpty() || !inv.args.isEmpty()) return false; if (!(inv.meth instanceof JCIdent)) return false; + if (tree.pos != expr.pos) return false; // Explicit super call return ((JCIdent) inv.meth).name.toString().equals("super"); } } @@ -377,6 +378,9 @@ public class PrettyPrinter extends JCTree.Visitor { private int dims(JCExpression vartype) { if (vartype instanceof JCArrayTypeTree) { return 1 + dims(((JCArrayTypeTree) vartype).elemtype); + } else if (isJcAnnotatedType(vartype)) { + JCTree underlyingType = readObject(vartype, "underlyingType", (JCTree) null); + if (underlyingType instanceof JCArrayTypeTree) return 1 + dims (((JCArrayTypeTree) underlyingType).elemtype); } return 0; @@ -624,13 +628,29 @@ public class PrettyPrinter extends JCTree.Visitor { printVarDef0(tree); } + private boolean innermostArrayBracketsAreVarargs = false; private void printVarDef0(JCVariableDecl tree) { boolean varargs = (tree.mods.flags & VARARGS) != 0; - if (varargs && tree.vartype instanceof JCArrayTypeTree) { - print(((JCArrayTypeTree) tree.vartype).elemtype); - print("..."); - } else { + + /* story time! + + in 'new int[5][6];', the 5 is the outermost and the 6 is the innermost: That means: 5 int arrays, each capable of containing 6 elements. + But that's actually a crazy way to read it; you'd think that in FOO[], you should interpret that as 'an array of FOO', but that's not correct; + if FOO is for example 'int[]', it's: "Modify the component type of FOO to be an array of whatever it was before.. unless FOO isn't an array, in which case, + this is an array of FOO". Which is weird. + + This is particularly poignant with vargs. In: "int[]... x", the ... are actually the _INNER_ type even though varargs by definition is a modification of + how to interpret the outer. The JLS just sort of lets that be: To indicate varargs, replace the lexically last [] with dots even though that's the wrong + [] to modify! + + This becomes an utter shambles when annotations-on-arrays become involved. The annotation on the INNER most type is to be placed right before the ...; + and because of that, we have to do crazy stuff with this innermostArrayBracketsAreVarargs flag. + */ + try { + innermostArrayBracketsAreVarargs = varargs; print(tree.vartype); + } finally { + innermostArrayBracketsAreVarargs = false; } print(" "); print(tree.name); @@ -774,10 +794,7 @@ public class PrettyPrinter extends JCTree.Visitor { } @Override public void visitTypeArray(JCArrayTypeTree tree) { - JCTree elem = tree.elemtype; - while (elem instanceof JCWildcard) elem = ((JCWildcard) elem).inner; - print(elem); - print("[]"); + printTypeArray0(tree); } @Override public void visitNewArray(JCNewArray tree) { @@ -1456,6 +1473,21 @@ public class PrettyPrinter extends JCTree.Visitor { } } + private boolean jcAnnotatedTypeInit = false; + private Class<?> jcAnnotatedTypeClass = null; + + private boolean isJcAnnotatedType(Object o) { + if (o == null) return false; + if (jcAnnotatedTypeInit) return jcAnnotatedTypeClass == o.getClass(); + Class<?> c = o.getClass(); + if (c.getSimpleName().equals("JCAnnotatedType")) { + jcAnnotatedTypeClass = c; + jcAnnotatedTypeInit = true; + return true; + } + return false; + } + private void printMemberReference0(JCTree tree) { print(readObject(tree, "expr", (JCExpression) null)); print("::"); @@ -1514,10 +1546,57 @@ public class PrettyPrinter extends JCTree.Visitor { print(readObject(tree, "annotations", List.<JCExpression>nil()), " "); print(" "); print(((JCFieldAccess) underlyingType).name); + } else if (underlyingType instanceof JCArrayTypeTree) { + printTypeArray0(tree); } else { print(readObject(tree, "annotations", List.<JCExpression>nil()), " "); print(" "); print(underlyingType); } } + + private void printTypeArray0(JCTree tree) { + JCTree inner = tree; + int dimCount = 0; + + while (true) { + if (inner instanceof JCArrayTypeTree) { + inner = ((JCArrayTypeTree) inner).elemtype; + dimCount++; + continue; + } else if (isJcAnnotatedType(inner)) { + JCTree underlyingType = readObject(inner, "underlyingType", (JCTree) null); + if (underlyingType instanceof JCArrayTypeTree) { + inner = ((JCArrayTypeTree) underlyingType).elemtype; + dimCount++; + continue; + } + } + break; + } + + print(inner); + + inner = tree; + while (true) { + if (inner instanceof JCArrayTypeTree) { + dimCount--; + print((dimCount == 0 && innermostArrayBracketsAreVarargs) ? "..." : "[]"); + inner = ((JCArrayTypeTree) inner).elemtype; + continue; + } else if (isJcAnnotatedType(inner)) { + JCTree underlyingType = readObject(inner, "underlyingType", (JCTree) null); + if (underlyingType instanceof JCArrayTypeTree) { + dimCount--; + print(" "); + print(readObject(inner, "annotations", List.<JCExpression>nil()), " "); + print(" "); + print((dimCount == 0 && innermostArrayBracketsAreVarargs) ? "..." : "[]"); + inner = ((JCArrayTypeTree) underlyingType).elemtype; + continue; + } + } + break; + } + } } diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java index a6d745b6..0e74dfaf 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java +++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 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 @@ -392,8 +392,8 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable { private static void patchIdentifierEndReparse(ScriptManager sm) { sm.addScript(ScriptBuilder.wrapReturnValue() .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "retrieveIdentifierEndPosition")) - .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveIdentifierEndPosition", "int", "int", "int")) - .transplant().request(StackRequest.RETURN_VALUE, StackRequest.PARAM2).build()); + .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveIdentifierEndPosition", "int", "int", "int", "int")) + .transplant().request(StackRequest.RETURN_VALUE, StackRequest.PARAM1, StackRequest.PARAM2).build()); } private static void patchRetrieveEllipsisStartPosition(ScriptManager sm) { diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchDiagnostics.java b/src/eclipseAgent/lombok/eclipse/agent/PatchDiagnostics.java index 82c4f522..157d92a3 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchDiagnostics.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchDiagnostics.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -29,14 +29,19 @@ public class PatchDiagnostics { * checks, and throw the exact same exception (thus, effectively, we don't change how eclipse operates), but, we <em>do</em> provide a useful message. */ public static boolean setSourceRangeCheck(Object astNode, int startPosition, int length) { + String nodeTxt; if (startPosition >= 0 && length < 0) { + if (astNode == null) nodeTxt = "(NULL NODE)"; + else nodeTxt = astNode.getClass() + ": " + astNode.toString(); throw new IllegalArgumentException("startPos = " + startPosition + " and length is " + length + ".\n" + - "This breaks the rule that lengths are not allowed to be negative. Affected Node:\n" + astNode); + "This breaks the rule that lengths are not allowed to be negative. Affected Node:\n" + nodeTxt); } if (startPosition < 0 && length != 0) { + if (astNode == null) nodeTxt = "(NULL NODE)"; + else nodeTxt = astNode.getClass() + ": " + astNode.toString(); throw new IllegalArgumentException("startPos = " + startPosition + " and length is " + length + ".\n" + - "This breaks the rule that length must be 0 if startPosition is negative. Affected Node:\n" + astNode); + "This breaks the rule that length must be 0 if startPosition is negative. Affected Node:\n" + nodeTxt); } return false; diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java index ace97a4d..085c903f 100644..100755 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchExtensionMethodCompletionProposal.java @@ -78,7 +78,7 @@ public class PatchExtensionMethodCompletionProposal { } } } - return proposals.toArray(new IJavaCompletionProposal[proposals.size()]); + return proposals.toArray(new IJavaCompletionProposal[0]); } diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java index 3c70d81d..3741aba8 100644..100755 --- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java +++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2015 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 @@ -31,8 +31,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Stack; -import lombok.eclipse.EclipseAugments; - import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.IAnnotatable; import org.eclipse.jdt.core.IAnnotation; @@ -64,6 +62,8 @@ import org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner; import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil; +import lombok.eclipse.EclipseAugments; + /** These contain a mix of the following: * <ul> * <li> 'dependency free' method wrappers that cross the shadowloader barrier. @@ -476,8 +476,10 @@ final class PatchFixesHider { return original == -1 ? start : original; } - public static int fixRetrieveIdentifierEndPosition(int original, int end) { - return original == -1 ? end : original; + public static int fixRetrieveIdentifierEndPosition(int original, int start, int end) { + if (original == -1) return end; + if (original < start) return end; + return original; } public static int fixRetrieveEllipsisStartPosition(int original, int end) { @@ -551,7 +553,7 @@ final class PatchFixesHider { // Since Eclipse doesn't honor the "insert at specified location" for already existing members, // we'll just add them last newChildren.addAll(modifiedChildren); - return newChildren.toArray(new RewriteEvent[newChildren.size()]); + return newChildren.toArray(new RewriteEvent[0]); } public static int getTokenEndOffsetFixed(TokenScanner scanner, int token, int startOffset, Object domNode) throws CoreException { @@ -570,7 +572,7 @@ final class PatchFixesHider { for (IMethod m : methods) { if (m.getNameRange().getLength() > 0 && !m.getNameRange().equals(m.getSourceRange())) result.add(m); } - return result.size() == methods.length ? methods : result.toArray(new IMethod[result.size()]); + return result.size() == methods.length ? methods : result.toArray(new IMethod[0]); } public static SearchMatch[] removeGenerated(SearchMatch[] returnValue) { @@ -591,7 +593,7 @@ final class PatchFixesHider { } result.add(searchResult); } - return result.toArray(new SearchMatch[result.size()]); + return result.toArray(new SearchMatch[0]); } public static SearchResultGroup[] createFakeSearchResult(SearchResultGroup[] returnValue, diff --git a/src/utils/lombok/permit/Permit.java b/src/utils/lombok/permit/Permit.java index 00b8274c..9f0434b8 100644 --- a/src/utils/lombok/permit/Permit.java +++ b/src/utils/lombok/permit/Permit.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2018-20199 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.permit; import java.lang.reflect.AccessibleObject; @@ -84,6 +105,22 @@ public class Permit { return setAccessible(f); } + public static Field permissiveGetField(Class<?> c, String fName) { + try { + return getField(c, fName); + } catch (Exception ignore) { + return null; + } + } + + public static <T> T permissiveReadField(Class<T> type, Field f, Object instance) { + try { + return type.cast(f.get(instance)); + } catch (Exception ignore) { + return null; + } + } + public static <T> Constructor<T> getConstructor(Class<T> c, Class<?>... parameterTypes) throws NoSuchMethodException { return setAccessible(c.getDeclaredConstructor(parameterTypes)); } |