diff options
Diffstat (limited to 'src')
31 files changed, 488 insertions, 328 deletions
diff --git a/src/core/lombok/bytecode/ClassFileMetaData.java b/src/core/lombok/bytecode/ClassFileMetaData.java index 68b8bb7d..0dc6a6c8 100644 --- a/src/core/lombok/bytecode/ClassFileMetaData.java +++ b/src/core/lombok/bytecode/ClassFileMetaData.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Project Lombok Authors. + * 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 @@ -44,6 +44,9 @@ public class ClassFileMetaData { private static final byte METHOD_HANDLE = 15; private static final byte METHOD_TYPE = 16; private static final byte INVOKE_DYNAMIC = 18; + // New in java9: support for modules + private static final byte MODULE = 19; + private static final byte PACKAGE = 20; private static final int NOT_FOUND = -1; private static final int START_OF_CONSTANT_POOL = 8; @@ -79,6 +82,8 @@ public class ClassFileMetaData { case CLASS: case STRING: case METHOD_TYPE: + case MODULE: + case PACKAGE: position += 2; break; case METHOD_HANDLE: diff --git a/src/core/lombok/core/AnnotationProcessor.java b/src/core/lombok/core/AnnotationProcessor.java index 5531ad8e..5b4ef393 100644 --- a/src/core/lombok/core/AnnotationProcessor.java +++ b/src/core/lombok/core/AnnotationProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2014 The Project Lombok Authors. + * Copyright (C) 2009-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 @@ -40,6 +40,7 @@ import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; +import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic.Kind; @@ -163,7 +164,21 @@ public class AnnotationProcessor extends AbstractProcessor { for (ProcessorDescriptor proc : active) proc.process(annotations, roundEnv); - return false; + boolean onlyLombok = true; + boolean zeroElems = true; + for (TypeElement elem : annotations) { + zeroElems = false; + Name n = elem.getQualifiedName(); + if (n.length() > 7 && n.subSequence(0, 7).toString().equals("lombok.")) continue; + onlyLombok = false; + } + + // Normally we rely on the claiming processor to claim away all lombok annotations. + // One of the many Java9 oversights is that this 'process' API has not been fixed to address the point that 'files I want to look at' and 'annotations I want to claim' must be one and the same, + // and yet in java9 you can no longer have 2 providers for the same service, thus, if you go by module path, lombok no longer loads the ClaimingProcessor. + // This doesn't do as good a job, but it'll have to do. The only way to go from here, I think, is either 2 modules, or use reflection hackery to add ClaimingProcessor during our init. + + return onlyLombok && !zeroElems; } /** diff --git a/src/core/lombok/core/LombokInternalAliasing.java b/src/core/lombok/core/LombokInternalAliasing.java index 08764a5c..3dc1bfa2 100644 --- a/src/core/lombok/core/LombokInternalAliasing.java +++ b/src/core/lombok/core/LombokInternalAliasing.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 The Project Lombok Authors. + * Copyright (C) 2013-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 @@ -51,6 +51,7 @@ public class LombokInternalAliasing { Map<String, String> m2 = new HashMap<String, String>(); m2.put("lombok.experimental.Value", "lombok.Value"); m2.put("lombok.experimental.Builder", "lombok.Builder"); + m2.put("lombok.experimental.var", "lombok.var"); m2.put("lombok.Delegate", "lombok.experimental.Delegate"); ALIASES = Collections.unmodifiableMap(m2); } diff --git a/src/core/lombok/core/configuration/AllowHelper.java b/src/core/lombok/core/configuration/AllowHelper.java index 3873b055..1146ccde 100644 --- a/src/core/lombok/core/configuration/AllowHelper.java +++ b/src/core/lombok/core/configuration/AllowHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Project Lombok Authors. + * Copyright (C) 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 @@ -24,10 +24,8 @@ package lombok.core.configuration; import java.util.Collection; import java.util.Collections; -import lombok.ConfigurationKeys; - public final class AllowHelper { - private final static Collection<? extends ConfigurationKey<?>> ALLOWABLE = Collections.singleton(ConfigurationKeys.VAR_FLAG_USAGE); + private final static Collection<? extends ConfigurationKey<?>> ALLOWABLE = Collections.emptySet(); private AllowHelper() { // Prevent instantiation diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index f4705e5b..6b516904 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2017 The Project Lombok Authors. + * Copyright (C) 2013-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 @@ -171,11 +171,12 @@ public class HandlerUtil { } @SuppressWarnings({"all", "unchecked", "deprecation"}) - public static final List<Class<? extends java.lang.annotation.Annotation>> INVALID_ON_BUILDERS = Collections.unmodifiableList( - Arrays.<Class<? extends java.lang.annotation.Annotation>>asList( - Getter.class, Setter.class, Wither.class, ToString.class, EqualsAndHashCode.class, - RequiredArgsConstructor.class, AllArgsConstructor.class, NoArgsConstructor.class, - Data.class, Value.class, lombok.experimental.Value.class, FieldDefaults.class)); + public static final List<String> INVALID_ON_BUILDERS = Collections.unmodifiableList( + Arrays.<String>asList( + Getter.class.getName(), Setter.class.getName(), Wither.class.getName(), + ToString.class.getName(), EqualsAndHashCode.class.getName(), + RequiredArgsConstructor.class.getName(), AllArgsConstructor.class.getName(), NoArgsConstructor.class.getName(), + Data.class.getName(), Value.class.getName(), "lombok.experimental.Value", FieldDefaults.class.getName())); /** * Given the name of a field, return the 'base name' of that field. For example, {@code fFoobar} becomes {@code foobar} if {@code f} is in the prefix list. diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index f49fff7f..e36e80bc 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 The Project Lombok Authors. + * Copyright (C) 2009-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 @@ -197,17 +197,36 @@ public class EclipseHandlerUtil { TypeResolver resolver = new TypeResolver(node.getImportList()); return resolver.typeMatches(node, type.getName(), typeName); + } + + /** + * Checks if the given TypeReference node is likely to be a reference to the provided class. + * + * @param type An actual type. This method checks if {@code typeNode} is likely to be a reference to this type. + * @param node A Lombok AST node. Any node in the appropriate compilation unit will do (used to get access to import statements). + * @param typeRef A type reference to check. + */ + public static boolean typeMatches(String type, EclipseNode node, TypeReference typeRef) { + if (typeRef == null || typeRef.getTypeName() == null || typeRef.getTypeName().length == 0) return false; + String lastPartA = new String(typeRef.getTypeName()[typeRef.getTypeName().length -1]); + int lastIndex = type.lastIndexOf('.'); + String lastPartB = lastIndex == -1 ? type : type.substring(lastIndex + 1); + if (!lastPartA.equals(lastPartB)) return false; + String typeName = toQualifiedName(typeRef.getTypeName()); + TypeResolver resolver = new TypeResolver(node.getImportList()); + return resolver.typeMatches(node, type, typeName); } public static void sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(EclipseNode typeNode, EclipseNode errorNode) { List<String> disallowed = null; for (EclipseNode child : typeNode.down()) { if (child.getKind() != Kind.ANNOTATION) continue; - for (Class<? extends java.lang.annotation.Annotation> annType : INVALID_ON_BUILDERS) { + for (String annType : INVALID_ON_BUILDERS) { if (annotationTypeMatches(annType, child)) { if (disallowed == null) disallowed = new ArrayList<String>(); - disallowed.add(annType.getSimpleName()); + int lastIndex = annType.lastIndexOf('.'); + disallowed.add(lastIndex == -1 ? annType : annType.substring(lastIndex + 1)); } } } @@ -444,6 +463,24 @@ public class EclipseHandlerUtil { } } + public static boolean hasAnnotation(String type, EclipseNode node) { + if (node == null) return false; + if (type == null) return false; + switch (node.getKind()) { + case ARGUMENT: + case FIELD: + case LOCAL: + case TYPE: + case METHOD: + for (EclipseNode child : node.down()) { + if (annotationTypeMatches(type, child)) return true; + } + // intentional fallthrough + default: + return false; + } + } + public static EclipseNode findAnnotation(Class<? extends java.lang.annotation.Annotation> type, EclipseNode node) { if (node == null) return null; if (type == null) return null; @@ -472,6 +509,16 @@ public class EclipseHandlerUtil { return typeMatches(type, node, ((Annotation) node.get()).type); } + /** + * Checks if the provided annotation type is likely to be the intended type for the given annotation node. + * + * This is a guess, but a decent one. + */ + public static boolean annotationTypeMatches(String type, EclipseNode node) { + if (node.getKind() != Kind.ANNOTATION) return false; + return typeMatches(type, node, ((Annotation) node.get()).type); + } + public static TypeReference cloneSelfType(EclipseNode context) { return cloneSelfType(context, null); } diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 12b8f6bc..dd862393 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2017 The Project Lombok Authors. + * Copyright (C) 2013-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 @@ -185,8 +185,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { TypeDeclaration td = (TypeDeclaration) tdParent.get(); List<EclipseNode> allFields = new ArrayList<EclipseNode>(); - @SuppressWarnings("deprecation") - boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation(lombok.experimental.Value.class, parent)); + boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent)); for (EclipseNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) { FieldDeclaration fd = (FieldDeclaration) fieldNode.get(); EclipseNode isDefault = findAnnotation(Builder.Default.class, fieldNode); diff --git a/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java b/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java index da184d0b..be2b986d 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2017-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.eclipse.handlers; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; @@ -18,7 +39,7 @@ public class HandleBuilderDefault extends EclipseAnnotationHandler<Builder.Defau EclipseNode annotatedField = annotationNode.up(); if (annotatedField.getKind() != Kind.FIELD) return; EclipseNode classWithAnnotatedField = annotatedField.up(); - if (!hasAnnotation(Builder.class, classWithAnnotatedField)) { + if (!hasAnnotation(Builder.class, classWithAnnotatedField) && !hasAnnotation("lombok.experimental.Builder", classWithAnnotatedField)) { annotationNode.addWarning("@Builder.Default requires @Builder on the class for it to mean anything."); } } diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index 0d0f51db..75339f7c 100644 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -475,47 +475,62 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH public TypeReference createTypeReference(EclipseNode type, long p, ASTNode source, boolean addWildcards) { int pS = source.sourceStart; int pE = source.sourceEnd; List<String> list = new ArrayList<String>(); + List<Integer> genericsCount = addWildcards ? new ArrayList<Integer>() : null; + list.add(type.getName()); + if (addWildcards) genericsCount.add(arraySizeOf(((TypeDeclaration) type.get()).typeParameters)); + boolean staticContext = (((TypeDeclaration) type.get()).modifiers & Modifier.STATIC) != 0; EclipseNode tNode = type.up(); + while (tNode != null && tNode.getKind() == Kind.TYPE) { list.add(tNode.getName()); + if (addWildcards) genericsCount.add(staticContext ? 0 : arraySizeOf(((TypeDeclaration) tNode.get()).typeParameters)); + if (!staticContext) staticContext = (((TypeDeclaration) tNode.get()).modifiers & Modifier.STATIC) != 0; tNode = tNode.up(); } Collections.reverse(list); - - TypeDeclaration typeDecl = (TypeDeclaration) type.get(); - int typeParamCount = typeDecl.typeParameters == null ? 0 : typeDecl.typeParameters.length; - if (typeParamCount == 0) addWildcards = false; - TypeReference[] typeArgs = null; - if (addWildcards) { - typeArgs = new TypeReference[typeParamCount]; - for (int i = 0; i < typeParamCount; i++) { - typeArgs[i] = new Wildcard(Wildcard.UNBOUND); - typeArgs[i].sourceStart = pS; typeArgs[i].sourceEnd = pE; - setGeneratedBy(typeArgs[i], source); - } - } + if (addWildcards) Collections.reverse(genericsCount); if (list.size() == 1) { - if (addWildcards) { - return new ParameterizedSingleTypeReference(list.get(0).toCharArray(), typeArgs, 0, p); - } else { + if (!addWildcards || genericsCount.get(0) == 0) { return new SingleTypeReference(list.get(0).toCharArray(), p); + } else { + return new ParameterizedSingleTypeReference(list.get(0).toCharArray(), wildcardify(pS, pE, source, genericsCount.get(0)), 0, p); } } + + if (addWildcards) { + addWildcards = false; + for (int i : genericsCount) if (i > 0) addWildcards = true; + } + long[] ps = new long[list.size()]; char[][] tokens = new char[list.size()][]; for (int i = 0; i < list.size(); i++) { ps[i] = p; tokens[i] = list.get(i).toCharArray(); } - if (addWildcards) { - TypeReference[][] typeArgs2 = new TypeReference[tokens.length][]; - typeArgs2[typeArgs2.length - 1] = typeArgs; - return new ParameterizedQualifiedTypeReference(tokens, typeArgs2, 0, ps); - } else { - return new QualifiedTypeReference(tokens, ps); + + if (!addWildcards) return new QualifiedTypeReference(tokens, ps); + TypeReference[][] typeArgs2 = new TypeReference[tokens.length][]; + for (int i = 0; i < tokens.length; i++) typeArgs2[i] = wildcardify(pS, pE, source, genericsCount.get(i)); + return new ParameterizedQualifiedTypeReference(tokens, typeArgs2, 0, ps); + } + + private TypeReference[] wildcardify(int pS, int pE, ASTNode source, int count) { + if (count == 0) return null; + TypeReference[] typeArgs = new TypeReference[count]; + for (int i = 0; i < count; i++) { + typeArgs[i] = new Wildcard(Wildcard.UNBOUND); + typeArgs[i].sourceStart = pS; typeArgs[i].sourceEnd = pE; + setGeneratedBy(typeArgs[i], source); } + + return typeArgs; + } + + private int arraySizeOf(Object[] arr) { + return arr == null ? 0 : arr.length; } public MethodDeclaration createEquals(EclipseNode type, Collection<EclipseNode> fields, boolean callSuper, ASTNode source, FieldAccess fieldAccess, boolean needsCanEqual, List<Annotation> onParam) { @@ -683,7 +698,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH } else /* objects */ { /* final java.lang.Object this$fieldName = this.fieldName; */ /* final java.lang.Object other$fieldName = other.fieldName; */ - /* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false;; */ + /* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false; */ char[] thisDollarFieldName = ("this$" + field.getName()).toCharArray(); char[] otherDollarFieldName = ("other$" + field.getName()).toCharArray(); diff --git a/src/core/lombok/eclipse/handlers/HandleVal.java b/src/core/lombok/eclipse/handlers/HandleVal.java index d8901067..3742ac00 100644 --- a/src/core/lombok/eclipse/handlers/HandleVal.java +++ b/src/core/lombok/eclipse/handlers/HandleVal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2016 The Project Lombok Authors. + * 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 @@ -25,13 +25,14 @@ import static lombok.core.handlers.HandlerUtil.handleFlagUsage; import static lombok.eclipse.handlers.EclipseHandlerUtil.typeMatches; import lombok.ConfigurationKeys; import lombok.val; +import lombok.var; import lombok.core.HandlerPriority; import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseASTAdapter; import lombok.eclipse.EclipseASTVisitor; import lombok.eclipse.EclipseNode; -import lombok.experimental.var; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; import org.eclipse.jdt.internal.compiler.ast.ForStatement; import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; @@ -74,11 +75,18 @@ public class HandleVal extends EclipseASTAdapter { return; } - if (isVal && localNode.directUp().get() instanceof ForStatement) { + ASTNode parentRaw = localNode.directUp().get(); + + if (isVal && parentRaw instanceof ForStatement) { localNode.addError("'val' is not allowed in old-style for loops"); return; } + if (parentRaw instanceof ForStatement && ((ForStatement) parentRaw).initializations != null && ((ForStatement) parentRaw).initializations.length > 1) { + localNode.addError("'var' is not allowed in old-style for loops if there is more than 1 initializer"); + return; + } + if (local.initialization != null && local.initialization.getClass().getName().equals("org.eclipse.jdt.internal.compiler.ast.LambdaExpression")) { localNode.addError("'" + annotation + "' is not allowed with lambda expressions."); return; diff --git a/src/core/lombok/eclipse/handlers/SetGeneratedByVisitor.java b/src/core/lombok/eclipse/handlers/SetGeneratedByVisitor.java index b42761f4..89964914 100644 --- a/src/core/lombok/eclipse/handlers/SetGeneratedByVisitor.java +++ b/src/core/lombok/eclipse/handlers/SetGeneratedByVisitor.java @@ -369,11 +369,6 @@ public final class SetGeneratedByVisitor extends ASTVisitor { return super.visit(node, scope); } - @Override public boolean visit(ArrayInitializer node, ClassScope scope) { - fixPositions(setGeneratedBy(node, source)); - return super.visit(node, scope); - } - @Override public boolean visit(ArrayQualifiedTypeReference node, BlockScope scope) { fixPositions(setGeneratedBy(node, source)); return super.visit(node, scope); diff --git a/src/core/lombok/experimental/Builder.java b/src/core/lombok/experimental/Builder.java deleted file mode 100644 index 7b364bff..00000000 --- a/src/core/lombok/experimental/Builder.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2013-2017 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.experimental; - -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.*; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * The builder annotation creates a so-called 'builder' aspect to the class that is annotated or the class - * that contains a member which is annotated with {@code @Builder}. - * <p> - * If a member is annotated, it must be either a constructor or a method. If a class is annotated, - * then a private constructor is generated with all fields as arguments - * (as if {@code @AllArgsConstructor(AccessLevel.PRIVATE)} is present - * on the class), and it is as if this constructor has been annotated with {@code @Builder} instead. - * <p> - * The effect of {@code @Builder} is that an inner class is generated named <code><strong>T</strong>Builder</code>, - * with a private constructor. Instances of <code><strong>T</strong>Builder</code> are made with the - * method named {@code builder()} which is also generated for you in the class itself (not in the builder class). - * <p> - * The <code><strong>T</strong>Builder</code> class contains 1 method for each parameter of the annotated - * constructor / method (each field, when annotating a class), which returns the builder itself. - * The builder also has a <code>build()</code> method which returns a completed instance of the original type, - * created by passing all parameters as set via the various other methods in the builder to the constructor - * or method that was annotated with {@code @Builder}. The return type of this method will be the same - * as the relevant class, unless a method has been annotated, in which case it'll be equal to the - * return type of that method. - * <p> - * Complete documentation is found at <a href="https://projectlombok.org/features/Builder">the project lombok features page for @Builder</a>. - * <br> - * <p> - * Before: - * - * <pre> - * @Builder - * class Example { - * private int foo; - * private final String bar; - * } - * </pre> - * - * After: - * - * <pre> - * class Example<T> { - * private T foo; - * private final String bar; - * - * private Example(T foo, String bar) { - * this.foo = foo; - * this.bar = bar; - * } - * - * public static <T> ExampleBuilder<T> builder() { - * return new ExampleBuilder<T>(); - * } - * - * public static class ExampleBuilder<T> { - * private T foo; - * private String bar; - * - * private ExampleBuilder() {} - * - * public ExampleBuilder foo(T foo) { - * this.foo = foo; - * return this; - * } - * - * public ExampleBuilder bar(String bar) { - * this.bar = bar; - * return this; - * } - * - * @java.lang.Override public String toString() { - * return "ExampleBuilder(foo = " + foo + ", bar = " + bar + ")"; - * } - * - * public Example build() { - * return new Example(foo, bar); - * } - * } - * } - * </pre> - * - * @deprecated {@link lombok.Builder} has been promoted to the main package, so use that one instead. - */ -@Target({TYPE, METHOD, CONSTRUCTOR}) -@Retention(SOURCE) -@Deprecated -public @interface Builder { - /** @return Name of the method that creates a new builder instance. Default: {@code builder}. */ - String builderMethodName() default "builder"; - - /** @return Name of the method in the builder class that creates an instance of your {@code @Builder}-annotated class. */ - String buildMethodName() default "build"; - - /** - * Name of the builder class. - * - * Default for {@code @Builder} on types and constructors: {@code (TypeName)Builder}. - * <p> - * Default for {@code @Builder} on methods: {@code (ReturnTypeName)Builder}. - * - * @return Name of the builder class that will be generated (or if it already exists, will be filled with builder elements). - */ - String builderClassName() default ""; - - /** - * Normally the builder's 'set' methods are fluent, meaning, they have the same name as the field. Set this - * to {@code false} to name the setter method for field {@code someField}: {@code setSomeField}. - * <p> - * <strong>Default: true</strong> - * - * @return Whether to generate fluent methods (just {@code fieldName()} instead of {@code setFieldName()}). - */ - boolean fluent() default true; - - /** - * Normally the builder's 'set' methods are chaining, meaning, they return the builder so that you can chain - * calls to set methods. Set this to {@code false} to have these 'set' methods return {@code void} instead. - * <p> - * <strong>Default: true</strong> - * - * @return Whether to generate chaining methods (each build call returns itself instead of returning {@code void}). - */ - boolean chain() default true; -} diff --git a/src/core/lombok/experimental/Value.java b/src/core/lombok/experimental/Value.java deleted file mode 100644 index 06dbee13..00000000 --- a/src/core/lombok/experimental/Value.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2012-2017 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.experimental; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Generates a lot of code which fits with a class that is a representation of an immutable entity. - * <p> - * Equivalent to {@code @Getter @FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE) @RequiredArgsConstructor @ToString @EqualsAndHashCode}. - * <p> - * Complete documentation is found at <a href="https://projectlombok.org/features/Value">the project lombok features page for @Value</a>. - * - * @see lombok.Getter - * @see Wither - * @see lombok.RequiredArgsConstructor - * @see lombok.ToString - * @see lombok.EqualsAndHashCode - * @see lombok.Data - * @deprecated {@link lombok.Value} has been promoted to the main package, so use that one instead. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.SOURCE) -@Deprecated -public @interface Value { - /** - * If you specify a static constructor name, then the generated constructor will be private, and - * instead a static factory method is created that other classes can use to create instances. - * We suggest the name: "of", like so: - * - * <pre> - * public @Data(staticConstructor = "of") class Point { final int x, y; } - * </pre> - * - * Default: No static constructor, instead the normal constructor is public. - * - * @return Name of static 'constructor' method to generate (blank = generate a normal constructor). - */ - String staticConstructor() default ""; -} diff --git a/src/core/lombok/experimental/var.java b/src/core/lombok/experimental/var.java index d8de8b19..71cc141a 100644 --- a/src/core/lombok/experimental/var.java +++ b/src/core/lombok/experimental/var.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2013 The Project Lombok Authors. + * Copyright (C) 2010-2017 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 @@ -23,6 +23,9 @@ package lombok.experimental; /** * like val but not final + * + * @deprecated {@code var} has been promoted to the main package; use {@link lombok.var} instead. */ +@Deprecated public @interface var { } diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index af812498..45679fd3 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -125,6 +125,8 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { String nm = Source.instance(context).name(); int underscoreIdx = nm.indexOf('_'); if (underscoreIdx > -1) return Integer.parseInt(nm.substring(underscoreIdx + 1)); + // assume java9+ + return Integer.parseInt(nm); } catch (Exception ignore) {} return 6; } diff --git a/src/core/lombok/javac/apt/InterceptingJavaFileManager.java b/src/core/lombok/javac/apt/InterceptingJavaFileManager.java index 303bdc2f..9b58d111 100644 --- a/src/core/lombok/javac/apt/InterceptingJavaFileManager.java +++ b/src/core/lombok/javac/apt/InterceptingJavaFileManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 The Project Lombok Authors. + * 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 @@ -42,14 +42,14 @@ final class InterceptingJavaFileManager extends ForwardingJavaFileManager<JavaFi } @Override public JavaFileObject getJavaFileForOutput(Location location, String className, final Kind kind, FileObject sibling) throws IOException { - if (className.startsWith("lombok.dummy.ForceNewRound")) { + 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; - } + if (kind != Kind.CLASS) return fileObject; + return LombokFileObjects.createIntercepting(compiler, fileObject, className, diagnostics); } }
\ No newline at end of file diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index 5c7e47ee..9c0a2dfa 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 The Project Lombok Authors. + * Copyright (C) 2009-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 @@ -301,7 +301,10 @@ public class LombokProcessor extends AbstractProcessor { // Step 1: Take all CUs which aren't already in the map. Give them the first priority level. + String randomModuleName = null; + for (Element element : roundEnv.getRootElements()) { + if (randomModuleName == null) randomModuleName = getModuleNameFor(element); JCCompilationUnit unit = toUnit(element); if (unit == null) continue; if (roots.containsKey(unit)) continue; @@ -344,20 +347,22 @@ public class LombokProcessor extends AbstractProcessor { if (newLevels.isEmpty()) return false; newLevels.retainAll(priorityLevelsRequiringResolutionReset); - if (!newLevels.isEmpty()){ + if (!newLevels.isEmpty()) { // Force a new round to reset resolution. The next round will cause this method (process) to be called again. - forceNewRound((JavacFiler) processingEnv.getFiler()); + forceNewRound(randomModuleName, (JavacFiler) processingEnv.getFiler()); return false; } - // None of the new levels need resolution, so just keep going. + // None of the new levels need resolution, so just keep going. } } private int dummyCount = 0; - private void forceNewRound(JavacFiler filer) { + private void forceNewRound(String randomModuleName, JavacFiler filer) { if (!filer.newFiles()) { try { - JavaFileObject dummy = filer.createSourceFile("lombok.dummy.ForceNewRound" + (dummyCount++)); + String name = "lombok.dummy.ForceNewRound" + (dummyCount++); + if (randomModuleName != null) name = randomModuleName + "/" + name; + JavaFileObject dummy = filer.createSourceFile(name); Writer w = dummy.openWriter(); w.close(); } catch (Exception e) { @@ -368,6 +373,19 @@ public class LombokProcessor extends AbstractProcessor { } } + private String getModuleNameFor(Element element) { + while (element != null) { + if (element.getKind().name().equals("MODULE")) { + String n = element.getSimpleName().toString().trim(); + return n.isEmpty() ? null : n; + } + Element n = element.getEnclosingElement(); + if (n == element) return null; + element = n; + } + return null; + } + private JCCompilationUnit toUnit(Element element) { TreePath path = trees == null ? null : trees.getPath(element); if (path == null) return null; diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index d5a342e4..0631f12a 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -21,7 +21,6 @@ */ package lombok.javac.handlers; -import java.lang.annotation.Annotation; import java.util.ArrayList; import javax.lang.model.element.Modifier; @@ -119,9 +118,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { if (!checkName("builderClassName", builderClassName, annotationNode)) return; } - @SuppressWarnings("deprecation") - Class<? extends Annotation> oldExperimentalBuilder = lombok.experimental.Builder.class; - deleteAnnotationIfNeccessary(annotationNode, Builder.class, oldExperimentalBuilder); + deleteAnnotationIfNeccessary(annotationNode, Builder.class, "lombok.experimental.Builder"); JavacNode parent = annotationNode.up(); @@ -140,8 +137,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { tdParent = parent; JCClassDecl td = (JCClassDecl) tdParent.get(); ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>(); - @SuppressWarnings("deprecation") - boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation(lombok.experimental.Value.class, parent)); + boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent)); for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) { JCVariableDecl fd = (JCVariableDecl) fieldNode.get(); JavacNode isDefault = findAnnotation(Builder.Default.class, fieldNode, true); diff --git a/src/core/lombok/javac/handlers/HandleBuilderDefault.java b/src/core/lombok/javac/handlers/HandleBuilderDefault.java index 733aea5a..4c4ba0e8 100644 --- a/src/core/lombok/javac/handlers/HandleBuilderDefault.java +++ b/src/core/lombok/javac/handlers/HandleBuilderDefault.java @@ -1,3 +1,24 @@ +/* + * Copyright (C) 2017-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.handlers; import static lombok.javac.handlers.JavacHandlerUtil.*; @@ -16,12 +37,11 @@ import lombok.javac.JavacNode; @ProviderFor(JavacAnnotationHandler.class) @HandlerPriority(-1025) //HandleBuilder's level, minus one. public class HandleBuilderDefault extends JavacAnnotationHandler<Builder.Default> { - @SuppressWarnings("deprecation") @Override public void handle(AnnotationValues<Builder.Default> annotation, JCAnnotation ast, JavacNode annotationNode) { JavacNode annotatedField = annotationNode.up(); if (annotatedField.getKind() != Kind.FIELD) return; JavacNode classWithAnnotatedField = annotatedField.up(); - if (!hasAnnotation(Builder.class, classWithAnnotatedField) && !hasAnnotation(lombok.experimental.Builder.class, classWithAnnotatedField)) { + if (!hasAnnotation(Builder.class, classWithAnnotatedField) && !hasAnnotation("lombok.experimental.Builder", classWithAnnotatedField)) { annotationNode.addWarning("@Builder.Default requires @Builder on the class for it to mean anything."); deleteAnnotationIfNeccessary(annotationNode, Builder.Default.class); } diff --git a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java index da2db909..d8bfd154 100644 --- a/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java @@ -371,31 +371,44 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas public JCExpression createTypeReference(JavacNode type, boolean addWildcards) { java.util.List<String> list = new ArrayList<String>(); + java.util.List<Integer> genericsCount = addWildcards ? new ArrayList<Integer>() : null; + list.add(type.getName()); + if (addWildcards) genericsCount.add(((JCClassDecl) type.get()).typarams.size()); + boolean staticContext = (((JCClassDecl) type.get()).getModifiers().flags & Flags.STATIC) != 0; JavacNode tNode = type.up(); + while (tNode != null && tNode.getKind() == Kind.TYPE) { list.add(tNode.getName()); + if (addWildcards) genericsCount.add(staticContext ? 0 : ((JCClassDecl) tNode.get()).typarams.size()); + if (!staticContext) staticContext = (((JCClassDecl) tNode.get()).getModifiers().flags & Flags.STATIC) != 0; tNode = tNode.up(); } Collections.reverse(list); - JCClassDecl typeDecl = (JCClassDecl) type.get(); + if (addWildcards) Collections.reverse(genericsCount); JavacTreeMaker maker = type.getTreeMaker(); JCExpression chain = maker.Ident(type.toName(list.get(0))); + if (addWildcards) chain = wildcardify(maker, chain, genericsCount.get(0)); for (int i = 1; i < list.size(); i++) { chain = maker.Select(chain, type.toName(list.get(i))); + if (addWildcards) chain = wildcardify(maker, chain, genericsCount.get(i)); } - if (!addWildcards || typeDecl.typarams.length() == 0) return chain; + return chain; + } + + private JCExpression wildcardify(JavacTreeMaker maker, JCExpression expr, int count) { + if (count == 0) return expr; ListBuffer<JCExpression> wildcards = new ListBuffer<JCExpression>(); - for (int i = 0 ; i < typeDecl.typarams.length() ; i++) { + for (int i = 0 ; i < count ; i++) { wildcards.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null)); } - return maker.TypeApply(chain, wildcards.toList()); + return maker.TypeApply(expr, wildcards.toList()); } public JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source, List<JCAnnotation> onParam) { diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java index f0f6eb2a..14130bc4 100644 --- a/src/core/lombok/javac/handlers/HandleVal.java +++ b/src/core/lombok/javac/handlers/HandleVal.java @@ -26,7 +26,7 @@ import static lombok.javac.handlers.JavacHandlerUtil.*; import lombok.ConfigurationKeys; import lombok.val; import lombok.core.HandlerPriority; -import lombok.experimental.var; +import lombok.var; import lombok.javac.JavacASTAdapter; import lombok.javac.JavacASTVisitor; import lombok.javac.JavacNode; @@ -54,10 +54,10 @@ import com.sun.tools.javac.util.List; public class HandleVal extends JavacASTAdapter { private static boolean eq(String typeTreeToString, String key) { - return (typeTreeToString.equals(key) || typeTreeToString.equals("lombok." + key)); + return typeTreeToString.equals(key) || typeTreeToString.equals("lombok." + key) || typeTreeToString.equals("lombok.experimental." + key); } - @Override + @SuppressWarnings("deprecation") @Override public void visitLocal(JavacNode localNode, JCVariableDecl local) { JCTree typeTree = local.vartype; if (typeTree == null) return; @@ -77,6 +77,11 @@ public class HandleVal extends JavacASTAdapter { return; } + if (parentRaw instanceof JCForLoop && ((JCForLoop) parentRaw).getInitializer().size() > 1) { + localNode.addError("'var' is not allowed in old-style for loops if there is more than 1 initializer"); + return; + } + JCExpression rhsOfEnhancedForLoop = null; if (local.init == null) { if (parentRaw instanceof JCEnhancedForLoop) { @@ -98,6 +103,7 @@ public class HandleVal extends JavacASTAdapter { if (localNode.shouldDeleteLombokAnnotations()) { JavacHandlerUtil.deleteImportFromCompilationUnit(localNode, val.class.getName()); + JavacHandlerUtil.deleteImportFromCompilationUnit(localNode, lombok.experimental.var.class.getName()); JavacHandlerUtil.deleteImportFromCompilationUnit(localNode, var.class.getName()); } diff --git a/src/core/lombok/javac/handlers/HandleValue.java b/src/core/lombok/javac/handlers/HandleValue.java index 90f6a98d..3961085c 100644 --- a/src/core/lombok/javac/handlers/HandleValue.java +++ b/src/core/lombok/javac/handlers/HandleValue.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 The Project Lombok Authors. + * Copyright (C) 2012-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 @@ -24,8 +24,6 @@ package lombok.javac.handlers; import static lombok.core.handlers.HandlerUtil.*; import static lombok.javac.handlers.JavacHandlerUtil.*; -import java.lang.annotation.Annotation; - import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.core.AnnotationValues; @@ -50,12 +48,9 @@ import com.sun.tools.javac.tree.JCTree.JCModifiers; @HandlerPriority(-512) //-2^9; to ensure @EqualsAndHashCode and such pick up on this handler making the class final and messing with the fields' access levels, run earlier. public class HandleValue extends JavacAnnotationHandler<Value> { @Override public void handle(AnnotationValues<Value> annotation, JCAnnotation ast, JavacNode annotationNode) { - @SuppressWarnings("deprecation") - Class<? extends Annotation> oldExperimentalValue = lombok.experimental.Value.class; - handleFlagUsage(annotationNode, ConfigurationKeys.VALUE_FLAG_USAGE, "@Value"); - deleteAnnotationIfNeccessary(annotationNode, Value.class, oldExperimentalValue); + deleteAnnotationIfNeccessary(annotationNode, Value.class, "lombok.experimental.Value"); JavacNode typeNode = annotationNode.up(); boolean notAClass = !isClass(typeNode); diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 956ab446..584c78c5 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2017 The Project Lombok Authors. + * Copyright (C) 2009-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 @@ -162,6 +162,10 @@ public class JavacHandlerUtil { return node; } + public static boolean hasAnnotation(String type, JavacNode node) { + return hasAnnotation(type, node, false); + } + public static boolean hasAnnotation(Class<? extends Annotation> type, JavacNode node) { return hasAnnotation(type, node, false); } @@ -191,6 +195,27 @@ public class JavacHandlerUtil { } } + private static boolean hasAnnotation(String type, JavacNode node, boolean delete) { + if (node == null) return false; + if (type == null) return false; + switch (node.getKind()) { + case ARGUMENT: + case FIELD: + case LOCAL: + case TYPE: + case METHOD: + for (JavacNode child : node.down()) { + if (annotationTypeMatches(type, child)) { + if (delete) deleteAnnotationIfNeccessary(child, type); + return true; + } + } + // intentional fallthrough + default: + return false; + } + } + static JavacNode findAnnotation(Class<? extends Annotation> type, JavacNode node, boolean delete) { if (node == null) return null; if (type == null) return null; @@ -224,6 +249,17 @@ public class JavacHandlerUtil { } /** + * Checks if the Annotation AST Node provided is likely to be an instance of the provided annotation type. + * + * @param type An actual annotation type, such as {@code lombok.Getter.class}. + * @param node A Lombok AST node representing an annotation in source code. + */ + public static boolean annotationTypeMatches(String type, JavacNode node) { + if (node.getKind() != Kind.ANNOTATION) return false; + return typeMatches(type, node, ((JCAnnotation)node.get()).annotationType); + } + + /** * Checks if the given TypeReference node is likely to be a reference to the provided class. * * @param type An actual type. This method checks if {@code typeNode} is likely to be a reference to this type. @@ -231,10 +267,21 @@ public class JavacHandlerUtil { * @param typeNode A type reference to check. */ public static boolean typeMatches(Class<?> type, JavacNode node, JCTree typeNode) { + return typeMatches(type.getName(), node, typeNode); + } + + /** + * Checks if the given TypeReference node is likely to be a reference to the provided class. + * + * @param type An actual type. This method checks if {@code typeNode} is likely to be a reference to this type. + * @param node A Lombok AST node. Any node in the appropriate compilation unit will do (used to get access to import statements). + * @param typeNode A type reference to check. + */ + public static boolean typeMatches(String type, JavacNode node, JCTree typeNode) { String typeName = typeNode.toString(); TypeResolver resolver = new TypeResolver(node.getImportList()); - return resolver.typeMatches(node, type.getName(), typeName); + return resolver.typeMatches(node, type, typeName); } /** @@ -346,8 +393,7 @@ public class JavacHandlerUtil { * then removes any import statement that imports this exact annotation (not star imports). * Only does this if the DeleteLombokAnnotations class is in the context. */ - @SuppressWarnings("unchecked") - public static void deleteAnnotationIfNeccessary(JavacNode annotation, Class<? extends Annotation> annotationType) { + public static void deleteAnnotationIfNeccessary(JavacNode annotation, String annotationType) { deleteAnnotationIfNeccessary0(annotation, annotationType); } @@ -356,12 +402,29 @@ public class JavacHandlerUtil { * then removes any import statement that imports this exact annotation (not star imports). * Only does this if the DeleteLombokAnnotations class is in the context. */ - @SuppressWarnings("unchecked") + public static void deleteAnnotationIfNeccessary(JavacNode annotation, Class<? extends Annotation> annotationType) { + deleteAnnotationIfNeccessary0(annotation, annotationType.getName()); + } + + /** + * Removes the annotation from javac's AST (it remains in lombok's AST), + * then removes any import statement that imports this exact annotation (not star imports). + * Only does this if the DeleteLombokAnnotations class is in the context. + */ public static void deleteAnnotationIfNeccessary(JavacNode annotation, Class<? extends Annotation> annotationType1, Class<? extends Annotation> annotationType2) { - deleteAnnotationIfNeccessary0(annotation, annotationType1, annotationType2); + deleteAnnotationIfNeccessary0(annotation, annotationType1.getName(), annotationType2.getName()); + } + + /** + * Removes the annotation from javac's AST (it remains in lombok's AST), + * then removes any import statement that imports this exact annotation (not star imports). + * Only does this if the DeleteLombokAnnotations class is in the context. + */ + public static void deleteAnnotationIfNeccessary(JavacNode annotation, Class<? extends Annotation> annotationType1, String annotationType2) { + deleteAnnotationIfNeccessary0(annotation, annotationType1.getName(), annotationType2); } - private static void deleteAnnotationIfNeccessary0(JavacNode annotation, Class<? extends Annotation>... annotationTypes) { + private static void deleteAnnotationIfNeccessary0(JavacNode annotation, String... annotationTypes) { if (inNetbeansEditor(annotation)) return; if (!annotation.shouldDeleteLombokAnnotations()) return; JavacNode parentNode = annotation.directUp(); @@ -390,8 +453,8 @@ public class JavacHandlerUtil { } parentNode.getAst().setChanged(); - for (Class<?> annotationType : annotationTypes) { - deleteImportFromCompilationUnit(annotation, annotationType.getName()); + for (String annotationType : annotationTypes) { + deleteImportFromCompilationUnit(annotation, annotationType); } } @@ -1405,9 +1468,10 @@ public class JavacHandlerUtil { public static void sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(JavacNode typeNode, JavacNode errorNode) { List<String> disallowed = List.nil(); for (JavacNode child : typeNode.down()) { - for (Class<? extends java.lang.annotation.Annotation> annType : INVALID_ON_BUILDERS) { + for (String annType : INVALID_ON_BUILDERS) { if (annotationTypeMatches(annType, child)) { - disallowed = disallowed.append(annType.getSimpleName()); + int lastIndex = annType.lastIndexOf('.'); + disallowed = disallowed.append(lastIndex == -1 ? annType : annType.substring(lastIndex + 1)); } } } diff --git a/src/core/lombok/var.java b/src/core/lombok/var.java new file mode 100644 index 00000000..63a70213 --- /dev/null +++ b/src/core/lombok/var.java @@ -0,0 +1,35 @@ +/* + * 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; + +/** + * Use {@code var} as the type of any local variable declaration (even in a {@code for} statement), and the type will be inferred from the initializing expression + * (any further assignments to the variable are not involved in this type inference). + * <p> + * For example: {@code var x = 10.0;} will infer {@code double}, and {@code var y = new ArrayList<String>();} will infer {@code ArrayList<String>}. + * <p> + * Note that this is an annotation type because {@code var x = 10;} will be desugared to {@code @var int x = 10;} + * <p> + * Complete documentation is found at <a href="https://projectlombok.org/features/var">the project lombok features page for @var</a>. + */ +public @interface var { +} diff --git a/src/core9/module-info.java b/src/core9/module-info.java new file mode 100644 index 00000000..87f819e2 --- /dev/null +++ b/src/core9/module-info.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 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. + */ +module lombok { + requires java.compiler; + requires java.instrument; + requires jdk.unsupported; + + exports lombok; + exports lombok.experimental; + exports lombok.extern.apachecommons; + exports lombok.extern.java; + exports lombok.extern.jbosslog; + exports lombok.extern.log4j; + exports lombok.extern.slf4j; + + provides javax.annotation.processing.Processor with lombok.launch.AnnotationProcessorHider.AnnotationProcessor; + provides org.mapstruct.ap.spi.AstModifyingAnnotationProcessor with lombok.launch.AnnotationProcessorHider.AstModificationNotifier; +} + diff --git a/src/delombok/lombok/delombok/DocCommentIntegrator.java b/src/delombok/lombok/delombok/DocCommentIntegrator.java index c3b07f32..bab0abd8 100644 --- a/src/delombok/lombok/delombok/DocCommentIntegrator.java +++ b/src/delombok/lombok/delombok/DocCommentIntegrator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010 The Project Lombok Authors. + * Copyright (C) 2009-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 @@ -74,7 +74,7 @@ public class DocCommentIntegrator { return out; } - private static final Pattern CONTENT_STRIPPER = Pattern.compile("^(?:\\s*\\*)?[ \\t]*(.*?)$", Pattern.MULTILINE); + private static final Pattern CONTENT_STRIPPER = Pattern.compile("^(?:\\s*\\*)?(.*?)$", Pattern.MULTILINE); @SuppressWarnings("unchecked") private boolean attach(JCCompilationUnit top, final JCTree node, CommentInfo cmt) { String docCommentContent = cmt.content; if (docCommentContent.startsWith("/**")) docCommentContent = docCommentContent.substring(3); diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java index e4dd7b26..3da37869 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchVal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 The Project Lombok Authors. + * 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 @@ -212,7 +212,7 @@ public class PatchVal { } private static boolean isVar(LocalDeclaration local, BlockScope scope) { - return is(local.type, scope, "lombok.experimental.var"); + return is(local.type, scope, "lombok.experimental.var") || is(local.type, scope, "lombok.var"); } private static boolean isVal(LocalDeclaration local, BlockScope scope) { diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java index 505eb767..46237dcf 100644 --- a/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java +++ b/src/eclipseAgent/lombok/eclipse/agent/PatchValEclipse.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 The Project Lombok Authors. + * 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 @@ -103,7 +103,7 @@ public class PatchValEclipse { } private static boolean couldBeVar(TypeReference type) { - return PatchVal.couldBe("lombok.experimental.var", type); + return PatchVal.couldBe("lombok.experimental.var", type) || PatchVal.couldBe("lombok.var", type); } public static void addFinalAndValAnnotationToSingleVariableDeclaration(Object converter, SingleVariableDeclaration out, LocalDeclaration in) { diff --git a/src/j9stubs/org/mapstruct/ap/spi/AstModifyingAnnotationProcessor.java b/src/j9stubs/org/mapstruct/ap/spi/AstModifyingAnnotationProcessor.java new file mode 100644 index 00000000..ffb99030 --- /dev/null +++ b/src/j9stubs/org/mapstruct/ap/spi/AstModifyingAnnotationProcessor.java @@ -0,0 +1,48 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.spi; + +import javax.lang.model.type.TypeMirror; + +/** + * A contract to be implemented by other annotation processors which - against the design philosophy of JSR 269 - alter + * the types under compilation. + * <p> + * This contract will be queried by MapStruct when examining types referenced by mappers to be generated, most notably + * the source and target types of mapping methods. If at least one AST-modifying processor announces further changes to + * such type, the generation of the affected mapper(s) will be deferred to a future round in the annnotation processing + * cycle. + * <p> + * Implementations are discovered via the service loader, i.e. a JAR providing an AST-modifying processor needs to + * declare its implementation in a file {@code META-INF/services/org.mapstruct.ap.spi.AstModifyingAnnotationProcessor}. + * + * @author Gunnar Morling + */ +//@org.mapstruct.util.Experimental +public interface AstModifyingAnnotationProcessor { + + /** + * Whether the specified type has been fully processed by this processor or not (i.e. this processor will amend the + * given type's structure after this invocation). + * + * @param type The type of interest + * @return {@code true} if this processor has fully processed the given type, {@code false} otherwise. + */ + boolean isTypeComplete(TypeMirror type); +}
\ No newline at end of file diff --git a/src/launch/lombok/launch/AnnotationProcessor.java b/src/launch/lombok/launch/AnnotationProcessor.java index 05c900ab..c4f922b9 100644 --- a/src/launch/lombok/launch/AnnotationProcessor.java +++ b/src/launch/lombok/launch/AnnotationProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2017 The Project Lombok Authors. + * Copyright (C) 2014-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 @@ -21,6 +21,7 @@ */ package lombok.launch; +import java.lang.reflect.Field; import java.util.Set; import javax.annotation.processing.AbstractProcessor; @@ -37,6 +38,8 @@ import javax.lang.model.type.TypeMirror; import org.mapstruct.ap.spi.AstModifyingAnnotationProcessor; +import sun.misc.Unsafe; + class AnnotationProcessorHider { public static class AstModificationNotifier implements AstModifyingAnnotationProcessor { @Override public boolean isTypeComplete(TypeMirror type) { @@ -65,11 +68,33 @@ class AnnotationProcessorHider { } @Override public void init(ProcessingEnvironment processingEnv) { + disableJava9SillyWarning(); AstModificationNotifierData.lombokInvoked = true; instance.init(processingEnv); super.init(processingEnv); } + // sunapi suppresses javac's warning about using Unsafe; 'all' suppresses eclipse's warning about the unspecified 'sunapi' key. Leave them both. + // Yes, javac's definition of the word 'all' is quite contrary to what the dictionary says it means. 'all' does NOT include 'sunapi' according to javac. + @SuppressWarnings({"sunapi", "all"}) + private void disableJava9SillyWarning() { + // JVM9 complains about using reflection to access packages from a module that aren't exported. This makes no sense; the whole point of reflection + // is to get past such issues. The only comment from the jigsaw team lead on this was some unspecified mumbling about security which makes no sense, + // as the SecurityManager is invoked to check such things. Therefore this warning is a bug, so we shall patch java to fix it. + + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + Unsafe u = (Unsafe) theUnsafe.get(null); + + Class<?> cls = Class.forName("jdk.internal.module.IllegalAccessLogger"); + Field logger = cls.getDeclaredField("logger"); + u.putObjectVolatile(cls, u.staticFieldOffset(logger), null); + } catch (Throwable t) { + // We shall ignore it; the effect of this code failing is that the user gets to see a warning they remove with various --add-opens magic. + } + } + @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { return instance.process(annotations, roundEnv); } @@ -82,7 +107,7 @@ class AnnotationProcessorHider { ClassLoader cl = Main.createShadowClassLoader(); try { Class<?> mc = cl.loadClass("lombok.core.AnnotationProcessor"); - return (AbstractProcessor) mc.newInstance(); + return (AbstractProcessor) mc.getDeclaredConstructor().newInstance(); } catch (Throwable t) { if (t instanceof Error) throw (Error) t; if (t instanceof RuntimeException) throw (RuntimeException) t; diff --git a/src/utils/lombok/javac/Javac.java b/src/utils/lombok/javac/Javac.java index 6f99463b..9ff4d22f 100644 --- a/src/utils/lombok/javac/Javac.java +++ b/src/utils/lombok/javac/Javac.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2015 The Project Lombok Authors. + * Copyright (C) 2009-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 @@ -63,8 +63,8 @@ public class Javac { /** Matches any of the 8 primitive names, such as {@code boolean}. */ private static final Pattern PRIMITIVE_TYPE_NAME_PATTERN = Pattern.compile("^(boolean|byte|short|int|long|float|double|char)$"); - private static final Pattern VERSION_PARSER = Pattern.compile("^(\\d{1,6})\\.(\\d{1,6}).*$"); - private static final Pattern SOURCE_PARSER = Pattern.compile("^JDK(\\d{1,6})_(\\d{1,6}).*$"); + private static final Pattern VERSION_PARSER = Pattern.compile("^(\\d{1,6})\\.?(\\d{1,6})?.*$"); + private static final Pattern SOURCE_PARSER = Pattern.compile("^JDK(\\d{1,6})_?(\\d{1,6})?.*$"); private static final AtomicInteger compilerVersion = new AtomicInteger(-1); @@ -79,11 +79,11 @@ public class Javac { Matcher m = VERSION_PARSER.matcher(JavaCompiler.version()); if (m.matches()) { int major = Integer.parseInt(m.group(1)); - int minor = Integer.parseInt(m.group(2)); if (major == 1) { - compilerVersion.set(minor); - return minor; + int minor = Integer.parseInt(m.group(2)); + return setVersion(minor); } + if (major >= 9) return setVersion(major); } } @@ -92,16 +92,19 @@ public class Javac { Matcher m = SOURCE_PARSER.matcher(name); if (m.matches()) { int major = Integer.parseInt(m.group(1)); - int minor = Integer.parseInt(m.group(2)); if (major == 1) { - compilerVersion.set(minor); - return minor; + int minor = Integer.parseInt(m.group(2)); + return setVersion(minor); } + if (major >= 9) return setVersion(major); } } - - compilerVersion.set(6); - return 6; + return setVersion(6); + } + + private static int setVersion(int version) { + compilerVersion.set(version); + return version; } private static final Class<?> DOCCOMMENTTABLE_CLASS; |