aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/lombok/ConfigurationKeys.java6
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java8
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleStandardException.java253
-rw-r--r--src/core/lombok/eclipse/handlers/HandleToString.java4
-rw-r--r--src/core/lombok/experimental/StandardException.java50
-rw-r--r--src/core/lombok/javac/handlers/HandleConstructor.java24
-rw-r--r--src/core/lombok/javac/handlers/HandleGetter.java3
-rw-r--r--src/core/lombok/javac/handlers/HandleNonNull.java34
-rw-r--r--src/core/lombok/javac/handlers/HandleSetter.java14
-rw-r--r--src/core/lombok/javac/handlers/HandleStandardException.java217
-rw-r--r--src/core/lombok/javac/handlers/HandleSuperBuilder.java2
-rw-r--r--src/core/lombok/javac/handlers/HandleUtilityClass.java5
-rw-r--r--src/core/lombok/javac/handlers/HandleWith.java7
-rw-r--r--src/core/lombok/javac/handlers/HandleWithBy.java7
-rw-r--r--src/core/lombok/javac/handlers/JavacHandlerUtil.java188
15 files changed, 682 insertions, 140 deletions
diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java
index ba66649b..b8cd442a 100644
--- a/src/core/lombok/ConfigurationKeys.java
+++ b/src/core/lombok/ConfigurationKeys.java
@@ -695,4 +695,10 @@ public class ConfigurationKeys {
*/
public static final ConfigurationKey<CheckerFrameworkVersion> CHECKER_FRAMEWORK = new ConfigurationKey<CheckerFrameworkVersion>("checkerframework", "If set with the version of checkerframework.org (in major.minor, or just 'true' for the latest supported version), create relevant checkerframework.org annotations for code lombok generates (default: false).") {};
+ /**
+ * lombok configuration: {@code lombok.standardException.flagUsage} = {@code WARNING} | {@code ERROR}.
+ *
+ * If set, <em>any</em> usage of {@code @StandardException} results in a warning / error.
+ */
+ public static final ConfigurationKey<FlagUsageType> STANDARD_EXCEPTION_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.standardException.flagUsage", "Emit a warning or error if @StandardException is used.") {};
}
diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
index 753c489c..12a3c315 100755
--- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
@@ -250,6 +250,8 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
setGeneratedBy(hashCodeCacheDecl.type, source);
}
+ private static final char[] HASH_CODE = "hashCode".toCharArray(), FLOAT_TO_INT_BITS = "floatToIntBits".toCharArray(), DOUBLE_TO_LONG_BITS = "doubleToLongBits".toCharArray();
+
public MethodDeclaration createHashCode(EclipseNode type, Collection<Included<EclipseNode, EqualsAndHashCode.Include>> members, boolean callSuper, boolean cacheHashCode, ASTNode source, FieldAccess fieldAccess) {
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long) pS << 32 | pE;
@@ -373,7 +375,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
floatToIntBits.sourceStart = pS; floatToIntBits.sourceEnd = pE;
setGeneratedBy(floatToIntBits, source);
floatToIntBits.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_FLOAT);
- floatToIntBits.selector = "floatToIntBits".toCharArray();
+ floatToIntBits.selector = FLOAT_TO_INT_BITS;
floatToIntBits.arguments = new Expression[] { fieldAccessor };
statements.add(createResultCalculation(source, floatToIntBits));
} else if (Arrays.equals(TypeConstants.DOUBLE, token)) {
@@ -382,7 +384,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
doubleToLongBits.sourceStart = pS; doubleToLongBits.sourceEnd = pE;
setGeneratedBy(doubleToLongBits, source);
doubleToLongBits.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_DOUBLE);
- doubleToLongBits.selector = "doubleToLongBits".toCharArray();
+ doubleToLongBits.selector = DOUBLE_TO_LONG_BITS;
doubleToLongBits.arguments = new Expression[] { fieldAccessor };
statements.add(createLocalDeclaration(source, dollarFieldName, TypeReference.baseTypeReference(TypeIds.T_long, 0), doubleToLongBits));
SingleNameReference copy1 = new SingleNameReference(dollarFieldName, p);
@@ -406,7 +408,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
hashCodeCall.sourceStart = pS; hashCodeCall.sourceEnd = pE;
setGeneratedBy(hashCodeCall, source);
hashCodeCall.receiver = copy1;
- hashCodeCall.selector = "hashCode".toCharArray();
+ hashCodeCall.selector = HASH_CODE;
NullLiteral nullLiteral = new NullLiteral(pS, pE);
setGeneratedBy(nullLiteral, source);
EqualExpression objIsNull = new EqualExpression(copy2, nullLiteral, OperatorIds.EQUAL_EQUAL);
diff --git a/src/core/lombok/eclipse/handlers/HandleStandardException.java b/src/core/lombok/eclipse/handlers/HandleStandardException.java
new file mode 100755
index 00000000..def6e495
--- /dev/null
+++ b/src/core/lombok/eclipse/handlers/HandleStandardException.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2021 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 lombok.AccessLevel;
+import lombok.ConfigurationKeys;
+import lombok.experimental.StandardException;
+import lombok.core.AST.Kind;
+import lombok.core.AnnotationValues;
+import lombok.eclipse.EclipseAnnotationHandler;
+import lombok.eclipse.EclipseNode;
+import lombok.eclipse.handlers.EclipseHandlerUtil.*;
+import lombok.spi.Provides;
+import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+
+import java.lang.reflect.Modifier;
+import java.util.*;
+
+import static lombok.core.handlers.HandlerUtil.handleFlagUsage;
+import static lombok.eclipse.Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
+import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
+
+@Provides
+public class HandleStandardException extends EclipseAnnotationHandler<StandardException> {
+ @Override
+ public void handle(AnnotationValues<StandardException> annotation, Annotation ast, EclipseNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.STANDARD_EXCEPTION_FLAG_USAGE, "@StandardException");
+
+ EclipseNode typeNode = annotationNode.up();
+ if (!isClass(typeNode)) {
+ annotationNode.addError("@StandardException is only supported on a class");
+ return;
+ }
+
+ TypeDeclaration classDef = (TypeDeclaration) typeNode.get();
+ if (classDef.superclass == null) {
+ annotationNode.addError("@StandardException requires that you extend a Throwable type");
+ return;
+ }
+
+ AccessLevel access = annotation.getInstance().access();
+
+ generateNoArgsConstructor(typeNode, access, annotationNode);
+ generateMsgOnlyConstructor(typeNode, access, annotationNode);
+ generateCauseOnlyConstructor(typeNode, access, annotationNode);
+ generateFullConstructor(typeNode, access, annotationNode);
+ }
+
+ private void generateNoArgsConstructor(EclipseNode typeNode, AccessLevel level, EclipseNode source) {
+ if (hasConstructor(typeNode) != MemberExistsResult.NOT_EXISTS) return;
+ int pS = source.get().sourceStart, pE = source.get().sourceEnd;
+
+ ExplicitConstructorCall explicitCall = new ExplicitConstructorCall(ExplicitConstructorCall.This);
+ explicitCall.arguments = new Expression[] {new NullLiteral(pS, pE), new NullLiteral(pS, pE)};
+ ConstructorDeclaration constructor = createConstructor(level, typeNode, false, false, source, explicitCall, null);
+ injectMethod(typeNode, constructor);
+ }
+
+ private void generateMsgOnlyConstructor(EclipseNode typeNode, AccessLevel level, EclipseNode source) {
+ if (hasConstructor(typeNode, String.class) != MemberExistsResult.NOT_EXISTS) return;
+ int pS = source.get().sourceStart, pE = source.get().sourceEnd;
+ long p = (long) pS << 32 | pE;
+
+ ExplicitConstructorCall explicitCall = new ExplicitConstructorCall(ExplicitConstructorCall.This);
+ explicitCall.arguments = new Expression[] {new SingleNameReference(MESSAGE, p), new NullLiteral(pS, pE)};
+ ConstructorDeclaration constructor = createConstructor(level, typeNode, true, false, source, explicitCall, null);
+ injectMethod(typeNode, constructor);
+ }
+
+ private void generateCauseOnlyConstructor(EclipseNode typeNode, AccessLevel level, EclipseNode source) {
+ if (hasConstructor(typeNode, Throwable.class) != MemberExistsResult.NOT_EXISTS) return;
+ int pS = source.get().sourceStart, pE = source.get().sourceEnd;
+ long p = (long) pS << 32 | pE;
+
+ ExplicitConstructorCall explicitCall = new ExplicitConstructorCall(ExplicitConstructorCall.This);
+ Expression causeNotNull = new EqualExpression(new SingleNameReference(CAUSE, p), new NullLiteral(pS, pE), OperatorIds.NOT_EQUAL);
+ MessageSend causeDotGetMessage = new MessageSend();
+ causeDotGetMessage.sourceStart = pS; causeDotGetMessage.sourceEnd = pE;
+ causeDotGetMessage.receiver = new SingleNameReference(CAUSE, p);
+ causeDotGetMessage.selector = GET_MESSAGE;
+ Expression messageExpr = new ConditionalExpression(causeNotNull, causeDotGetMessage, new NullLiteral(pS, pE));
+ explicitCall.arguments = new Expression[] {messageExpr, new SingleNameReference(CAUSE, p)};
+ ConstructorDeclaration constructor = createConstructor(level, typeNode, false, true, source, explicitCall, null);
+ injectMethod(typeNode, constructor);
+ }
+
+ private void generateFullConstructor(EclipseNode typeNode, AccessLevel level, EclipseNode source) {
+ if (hasConstructor(typeNode, String.class, Throwable.class) != MemberExistsResult.NOT_EXISTS) return;
+ int pS = source.get().sourceStart, pE = source.get().sourceEnd;
+ long p = (long) pS << 32 | pE;
+
+ ExplicitConstructorCall explicitCall = new ExplicitConstructorCall(ExplicitConstructorCall.Super);
+ explicitCall.arguments = new Expression[] {new SingleNameReference(MESSAGE, p)};
+ Expression causeNotNull = new EqualExpression(new SingleNameReference(CAUSE, p), new NullLiteral(pS, pE), OperatorIds.NOT_EQUAL);
+ MessageSend causeDotInitCause = new MessageSend();
+ causeDotInitCause.sourceStart = pS; causeDotInitCause.sourceEnd = pE;
+ causeDotInitCause.receiver = new SuperReference(pS, pE);
+ causeDotInitCause.selector = INIT_CAUSE;
+ causeDotInitCause.arguments = new Expression[] {new SingleNameReference(CAUSE, p)};
+ IfStatement ifs = new IfStatement(causeNotNull, causeDotInitCause, pS, pE);
+ ConstructorDeclaration constructor = createConstructor(level, typeNode, true, true, source, explicitCall, ifs);
+ injectMethod(typeNode, constructor);
+ }
+
+ /**
+ * Checks if a constructor with the provided parameters exists under the type node.
+ */
+ public static MemberExistsResult hasConstructor(EclipseNode node, Class<?>... paramTypes) {
+ node = upToTypeNode(node);
+
+ if (node != null && node.get() instanceof TypeDeclaration) {
+ TypeDeclaration typeDecl = (TypeDeclaration) node.get();
+ if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) {
+ if (def instanceof ConstructorDeclaration) {
+ if ((def.bits & ASTNode.IsDefaultConstructor) != 0) continue;
+ if (!paramsMatch(node, def.arguments, paramTypes)) continue;
+ return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK;
+ }
+ }
+ }
+
+ return MemberExistsResult.NOT_EXISTS;
+ }
+
+ private static boolean paramsMatch(EclipseNode node, Argument[] a, Class<?>[] b) {
+ if (a == null) return b == null || b.length == 0;
+ if (b == null) return a.length == 0;
+ if (a.length != b.length) return false;
+
+ for (int i = 0; i < a.length; i++) {
+ if (!typeMatches(b[i], node, a[i].type)) return false;
+ }
+ return true;
+ }
+
+ private static final char[][] JAVA_BEANS_CONSTRUCTORPROPERTIES = new char[][] { "java".toCharArray(), "beans".toCharArray(), "ConstructorProperties".toCharArray() };
+ private static final char[] MESSAGE = "message".toCharArray(), CAUSE = "cause".toCharArray(), GET_MESSAGE = "getMessage".toCharArray(), INIT_CAUSE = "initCause".toCharArray();
+
+ public static Annotation[] createConstructorProperties(ASTNode source, boolean msgParam, boolean causeParam) {
+ if (!msgParam && !causeParam) return null;
+
+ int pS = source.sourceStart, pE = source.sourceEnd;
+ long p = (long) pS << 32 | pE;
+ long[] poss = new long[3];
+ Arrays.fill(poss, p);
+
+ QualifiedTypeReference constructorPropertiesType = new QualifiedTypeReference(JAVA_BEANS_CONSTRUCTORPROPERTIES, poss);
+ setGeneratedBy(constructorPropertiesType, source);
+ SingleMemberAnnotation ann = new SingleMemberAnnotation(constructorPropertiesType, pS);
+ ann.declarationSourceEnd = pE;
+
+ ArrayInitializer fieldNames = new ArrayInitializer();
+ fieldNames.sourceStart = pS;
+ fieldNames.sourceEnd = pE;
+ fieldNames.expressions = new Expression[(msgParam && causeParam) ? 2 : 1];
+
+ int ctr = 0;
+ if (msgParam) {
+ fieldNames.expressions[ctr] = new StringLiteral(MESSAGE, pS, pE, 0);
+ setGeneratedBy(fieldNames.expressions[ctr], source);
+ ctr++;
+ }
+ if (causeParam) {
+ fieldNames.expressions[ctr] = new StringLiteral(CAUSE, pS, pE, 0);
+ setGeneratedBy(fieldNames.expressions[ctr], source);
+ ctr++;
+ }
+
+ ann.memberValue = fieldNames;
+ setGeneratedBy(ann, source);
+ setGeneratedBy(ann.memberValue, source);
+ return new Annotation[] { ann };
+ }
+
+ @SuppressWarnings("deprecation") public static ConstructorDeclaration createConstructor(AccessLevel level, EclipseNode typeNode, boolean msgParam, boolean causeParam, EclipseNode sourceNode, ExplicitConstructorCall explicitCall, Statement extra) {
+ ASTNode source = sourceNode.get();
+ TypeDeclaration typeDeclaration = ((TypeDeclaration) typeNode.get());
+ int pS = source.sourceStart, pE = source.sourceEnd;
+ long p = (long) pS << 32 | pE;
+
+ boolean addConstructorProperties;
+ if ((!msgParam && !causeParam) || isLocalType(typeNode)) {
+ addConstructorProperties = false;
+ } else {
+ Boolean v = typeNode.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_ADD_CONSTRUCTOR_PROPERTIES);
+ addConstructorProperties = v != null ? v.booleanValue() :
+ Boolean.FALSE.equals(typeNode.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_SUPPRESS_CONSTRUCTOR_PROPERTIES));
+ }
+
+ ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) typeNode.top().get()).compilationResult);
+
+ constructor.modifiers = toEclipseModifier(level);
+ constructor.selector = typeDeclaration.name;
+ constructor.thrownExceptions = null;
+ constructor.typeParameters = null;
+ constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
+ constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = pS;
+ constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = pE;
+ constructor.arguments = null;
+
+ List<Argument> params = new ArrayList<Argument>();
+
+ if (msgParam) {
+ TypeReference typeRef = new QualifiedTypeReference(TypeConstants.JAVA_LANG_STRING, new long[] {p, p, p});
+ Argument parameter = new Argument(MESSAGE, p, typeRef, Modifier.FINAL);
+ params.add(parameter);
+ }
+ if (causeParam) {
+ TypeReference typeRef = new QualifiedTypeReference(TypeConstants.JAVA_LANG_THROWABLE, new long[] {p, p, p});
+ Argument parameter = new Argument(CAUSE, p, typeRef, Modifier.FINAL);
+ params.add(parameter);
+ }
+
+ explicitCall.sourceStart = pS;
+ explicitCall.sourceEnd = pE;
+ constructor.constructorCall = explicitCall;
+ constructor.statements = extra != null ? new Statement[] {extra} : null;
+ constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[0]);
+
+ Annotation[] constructorProperties = null;
+ if (addConstructorProperties) constructorProperties = createConstructorProperties(source, msgParam, causeParam);
+ constructor.annotations = copyAnnotations(source, constructorProperties);
+ constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope);
+ return constructor;
+ }
+
+ public static boolean isLocalType(EclipseNode type) {
+ Kind kind = type.up().getKind();
+ if (kind == Kind.COMPILATION_UNIT) return false;
+ if (kind == Kind.TYPE) return isLocalType(type.up());
+ return true;
+ }
+}
diff --git a/src/core/lombok/eclipse/handlers/HandleToString.java b/src/core/lombok/eclipse/handlers/HandleToString.java
index 72491277..171402b3 100644
--- a/src/core/lombok/eclipse/handlers/HandleToString.java
+++ b/src/core/lombok/eclipse/handlers/HandleToString.java
@@ -161,12 +161,12 @@ public class HandleToString extends EclipseAnnotationHandler<ToString> {
String typeName = getTypeName(type);
boolean isEnum = type.isEnumType();
-
+
char[] suffix = ")".toCharArray();
String infixS = ", ";
char[] infix = infixS.toCharArray();
int pS = source.sourceStart, pE = source.sourceEnd;
- long p = (long)pS << 32 | pE;
+ long p = (long) pS << 32 | pE;
final int PLUS = OperatorIds.PLUS;
String prefix;
diff --git a/src/core/lombok/experimental/StandardException.java b/src/core/lombok/experimental/StandardException.java
new file mode 100644
index 00000000..b04ac2ee
--- /dev/null
+++ b/src/core/lombok/experimental/StandardException.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 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;
+
+import lombok.AccessLevel;
+
+/**
+ * Put on any class that extends some {@code java.lang.Throwable} type to add the 4 common exception constructors.
+ *
+ * Specifically, all 4 constructors derived from the combinatorial explosion of {@code String message} and {@code Throwable cause}.
+ * You may write any or all of these 4 constructors by hand; lombok will only generate the missing ones.
+ * <p>
+ * All but the full {@code (String message, Throwable cause)} constructor are implemented as a {@code this(msg, cause)} call; it is therefore
+ * possibly to write code to run on construction by writing just the {@code (String message, Throwable cause)} constructor.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.SOURCE)
+public @interface StandardException {
+ /**
+ * Sets the access level of the generated constuctors. By default, generated constructors are {@code public}.
+ * Note: This does nothing if you write your own constructors (we won't change their access levels).
+ *
+ * @return The constructors will be generated with this access modifier.
+ */
+ AccessLevel access() default lombok.AccessLevel.PUBLIC;
+}
diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java
index 9c74ca0e..dc70e2ce 100644
--- a/src/core/lombok/javac/handlers/HandleConstructor.java
+++ b/src/core/lombok/javac/handlers/HandleConstructor.java
@@ -26,8 +26,6 @@ import static lombok.javac.Javac.*;
import static lombok.javac.handlers.JavacHandlerUtil.*;
import com.sun.tools.javac.code.Flags;
-import com.sun.tools.javac.code.Symbol.ClassSymbol;
-import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCBlock;
@@ -55,7 +53,6 @@ import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.configuration.CheckerFrameworkVersion;
import lombok.delombok.LombokOptionsFactory;
-import lombok.javac.Javac;
import lombok.javac.JavacAnnotationHandler;
import lombok.javac.JavacNode;
import lombok.javac.JavacTreeMaker;
@@ -243,30 +240,17 @@ public class HandleConstructor {
if (noArgs && noArgsConstructorExists(typeNode)) return;
- ListBuffer<Type> argTypes = new ListBuffer<Type>();
- for (JavacNode fieldNode : fields) {
- Type mirror = getMirrorForFieldType(fieldNode);
- if (mirror == null) {
- argTypes = null;
- break;
- }
- argTypes.append(mirror);
- }
- List<Type> argTypes_ = argTypes == null ? null : argTypes.toList();
-
if (!(skipIfConstructorExists != SkipIfConstructorExists.NO && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS)) {
JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, onConstructor, typeNode, fields, allToDefault, source);
- injectMethod(typeNode, constr, argTypes_, Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID));
+ injectMethod(typeNode, constr);
}
- generateStaticConstructor(staticConstrRequired, typeNode, staticName, level, allToDefault, fields, source, argTypes_);
+ generateStaticConstructor(staticConstrRequired, typeNode, staticName, level, allToDefault, fields, source);
}
- private void generateStaticConstructor(boolean staticConstrRequired, JavacNode typeNode, String staticName, AccessLevel level, boolean allToDefault, List<JavacNode> fields, JavacNode source, List<Type> argTypes_) {
+ private void generateStaticConstructor(boolean staticConstrRequired, JavacNode typeNode, String staticName, AccessLevel level, boolean allToDefault, List<JavacNode> fields, JavacNode source) {
if (staticConstrRequired) {
- ClassSymbol sym = ((JCClassDecl) typeNode.get()).sym;
- Type returnType = sym == null ? null : sym.type;
JCMethodDecl staticConstr = createStaticConstructor(staticName, level, typeNode, allToDefault ? List.<JavacNode>nil() : fields, source);
- injectMethod(typeNode, staticConstr, argTypes_, returnType);
+ injectMethod(typeNode, staticConstr);
}
}
diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java
index 8f6de9bb..7a7e41f9 100644
--- a/src/core/lombok/javac/handlers/HandleGetter.java
+++ b/src/core/lombok/javac/handlers/HandleGetter.java
@@ -46,7 +46,6 @@ import lombok.javac.JavacTreeMaker.TypeTag;
import lombok.spi.Provides;
import com.sun.tools.javac.code.Flags;
-import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCBinary;
@@ -214,7 +213,7 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC);
- injectMethod(fieldNode.up(), createGetter(access, fieldNode, fieldNode.getTreeMaker(), source, lazy, onMethod), List.<Type>nil(), getMirrorForFieldType(fieldNode));
+ injectMethod(fieldNode.up(), createGetter(access, fieldNode, fieldNode.getTreeMaker(), source, lazy, onMethod));
}
public JCMethodDecl createGetter(long access, JavacNode field, JavacTreeMaker treeMaker, JavacNode source, boolean lazy, List<JCAnnotation> onMethod) {
diff --git a/src/core/lombok/javac/handlers/HandleNonNull.java b/src/core/lombok/javac/handlers/HandleNonNull.java
index 786a7659..fe66432a 100644
--- a/src/core/lombok/javac/handlers/HandleNonNull.java
+++ b/src/core/lombok/javac/handlers/HandleNonNull.java
@@ -71,7 +71,7 @@ import lombok.spi.Provides;
@Provides
@HandlerPriority(value = 512) // 2^9; onParameter=@__(@NonNull) has to run first.
public class HandleNonNull extends JavacAnnotationHandler<NonNull> {
- private JCMethodDecl createRecordArgslessConstructor(JavacNode typeNode, JavacNode source) {
+ private JCMethodDecl createRecordArgslessConstructor(JavacNode typeNode, JavacNode source, JCMethodDecl existingCtr) {
JavacTreeMaker maker = typeNode.getTreeMaker();
java.util.List<JCVariableDecl> fields = new ArrayList<JCVariableDecl>();
@@ -94,8 +94,18 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> {
JCModifiers mods = maker.Modifiers(toJavacModifier(AccessLevel.PUBLIC) | COMPACT_RECORD_CONSTRUCTOR, List.<JCAnnotation>nil());
JCBlock body = maker.Block(0L, List.<JCStatement>nil());
- JCMethodDecl constr = maker.MethodDef(mods, typeNode.toName("<init>"), null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(), body, null);
- return recursiveSetGeneratedBy(constr, source);
+ if (existingCtr == null) {
+ JCMethodDecl constr = maker.MethodDef(mods, typeNode.toName("<init>"), null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(), body, null);
+ return recursiveSetGeneratedBy(constr, source);
+ } else {
+ existingCtr.mods = mods;
+ existingCtr.params = params.toList();
+ existingCtr.body = body;
+ existingCtr = recursiveSetGeneratedBy(existingCtr, source);
+ addSuppressWarningsAll(existingCtr.mods, typeNode, typeNode.getNodeFor(getGeneratedBy(existingCtr)), typeNode.getContext());
+ addGenerated(existingCtr.mods, typeNode, typeNode.getNodeFor(getGeneratedBy(existingCtr)), typeNode.getContext());
+ return existingCtr;
+ }
}
/**
@@ -113,16 +123,17 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> {
JCClassDecl cDecl = (JCClassDecl) typeNode.get();
if ((cDecl.mods.flags & RECORD) == 0) return answer;
- ListBuffer<JCTree> newDefs = new ListBuffer<JCTree>();
boolean generateConstructor = false;
+ JCMethodDecl existingCtr = null;
+
for (JCTree def : cDecl.defs) {
- boolean remove = false;
if (def instanceof JCMethodDecl) {
JCMethodDecl md = (JCMethodDecl) def;
if (md.name.contentEquals("<init>")) {
if ((md.mods.flags & Flags.GENERATEDCONSTR) != 0) {
- remove = true;
+ existingCtr = md;
+ existingCtr.mods.flags = existingCtr.mods.flags & ~Flags.GENERATEDCONSTR;
generateConstructor = true;
} else {
if (!isTolerate(typeNode, md)) {
@@ -134,13 +145,16 @@ public class HandleNonNull extends JavacAnnotationHandler<NonNull> {
}
}
}
- if (!remove) newDefs.append(def);
}
if (generateConstructor) {
- cDecl.defs = newDefs.toList();
- JCMethodDecl ctr = createRecordArgslessConstructor(typeNode, source);
- injectMethod(typeNode, ctr);
+ JCMethodDecl ctr;
+ if (existingCtr != null) {
+ ctr = createRecordArgslessConstructor(typeNode, source, existingCtr);
+ } else {
+ ctr = createRecordArgslessConstructor(typeNode, source, null);
+ injectMethod(typeNode, ctr);
+ }
answer = answer.prepend(ctr);
}
diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java
index 5c34f9f5..a0634494 100644
--- a/src/core/lombok/javac/handlers/HandleSetter.java
+++ b/src/core/lombok/javac/handlers/HandleSetter.java
@@ -40,8 +40,6 @@ import lombok.javac.JavacTreeMaker;
import lombok.spi.Provides;
import com.sun.tools.javac.code.Flags;
-import com.sun.tools.javac.code.Symbol.ClassSymbol;
-import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCBlock;
@@ -184,17 +182,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
long access = toJavacModifier(level) | (fieldDecl.mods.flags & Flags.STATIC);
JCMethodDecl createdSetter = createSetter(access, fieldNode, fieldNode.getTreeMaker(), sourceNode, onMethod, onParam);
- Type fieldType = getMirrorForFieldType(fieldNode);
- Type returnType;
-
- if (shouldReturnThis(fieldNode)) {
- ClassSymbol sym = ((JCClassDecl) fieldNode.up().get()).sym;
- returnType = sym == null ? null : sym.type;
- } else {
- returnType = Javac.createVoidType(fieldNode.getSymbolTable(), CTC_VOID);
- }
-
- injectMethod(fieldNode.up(), createdSetter, fieldType == null ? null : List.of(fieldType), returnType);
+ injectMethod(fieldNode.up(), createdSetter);
}
public static JCMethodDecl createSetter(long access, JavacNode field, JavacTreeMaker treeMaker, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam) {
diff --git a/src/core/lombok/javac/handlers/HandleStandardException.java b/src/core/lombok/javac/handlers/HandleStandardException.java
new file mode 100644
index 00000000..dd764233
--- /dev/null
+++ b/src/core/lombok/javac/handlers/HandleStandardException.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2021 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 com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Name;
+import lombok.AccessLevel;
+import lombok.ConfigurationKeys;
+import lombok.experimental.StandardException;
+import lombok.core.AST.Kind;
+import lombok.core.AnnotationValues;
+import lombok.delombok.LombokOptionsFactory;
+import lombok.javac.Javac;
+import lombok.javac.JavacAnnotationHandler;
+import lombok.javac.JavacNode;
+import lombok.javac.JavacTreeMaker;
+import lombok.javac.handlers.JavacHandlerUtil.*;
+import lombok.spi.Provides;
+
+import static lombok.core.handlers.HandlerUtil.handleFlagUsage;
+import static lombok.javac.Javac.*;
+import static lombok.javac.handlers.JavacHandlerUtil.*;
+
+@Provides
+public class HandleStandardException extends JavacAnnotationHandler<StandardException> {
+ @Override
+ public void handle(AnnotationValues<StandardException> annotation, JCAnnotation ast, JavacNode annotationNode) {
+ handleFlagUsage(annotationNode, ConfigurationKeys.STANDARD_EXCEPTION_FLAG_USAGE, "@StandardException");
+ deleteAnnotationIfNeccessary(annotationNode, StandardException.class);
+ deleteImportFromCompilationUnit(annotationNode, "lombok.AccessLevel");
+ JavacNode typeNode = annotationNode.up();
+
+ if (!isClass(typeNode)) {
+ annotationNode.addError("@StandardException is only supported on a class");
+ return;
+ }
+
+ JCTree extending = Javac.getExtendsClause((JCClassDecl) typeNode.get());
+ if (extending == null) {
+ annotationNode.addError("@StandardException requires that you extend a Throwable type");
+ return;
+ }
+
+ AccessLevel access = annotation.getInstance().access();
+ if (access == null) access = AccessLevel.PUBLIC;
+ if (access == AccessLevel.NONE) {
+ annotationNode.addError("AccessLevel.NONE is not valid here");
+ access = AccessLevel.PUBLIC;
+ }
+
+ generateNoArgsConstructor(typeNode, access, annotationNode);
+ generateMsgOnlyConstructor(typeNode, access, annotationNode);
+ generateCauseOnlyConstructor(typeNode, access, annotationNode);
+ generateFullConstructor(typeNode, access, annotationNode);
+ }
+
+ private void generateNoArgsConstructor(JavacNode typeNode, AccessLevel level, JavacNode source) {
+ if (hasConstructor(typeNode) != MemberExistsResult.NOT_EXISTS) return;
+ JavacTreeMaker maker = typeNode.getTreeMaker();
+
+ List<JCExpression> args = List.<JCExpression>of(maker.Literal(CTC_BOT, null), maker.Literal(CTC_BOT, null));
+ JCStatement thisCall = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(typeNode.toName("this")), args));
+ JCMethodDecl constr = createConstructor(level, typeNode, false, false, source, List.of(thisCall));
+ injectMethod(typeNode, constr);
+ }
+
+ private void generateMsgOnlyConstructor(JavacNode typeNode, AccessLevel level, JavacNode source) {
+ if (hasConstructor(typeNode, String.class) != MemberExistsResult.NOT_EXISTS) return;
+ JavacTreeMaker maker = typeNode.getTreeMaker();
+
+ List<JCExpression> args = List.<JCExpression>of(maker.Ident(typeNode.toName("message")), maker.Literal(CTC_BOT, null));
+ JCStatement thisCall = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(typeNode.toName("this")), args));
+ JCMethodDecl constr = createConstructor(level, typeNode, true, false, source, List.of(thisCall));
+ injectMethod(typeNode, constr);
+ }
+
+ private void generateCauseOnlyConstructor(JavacNode typeNode, AccessLevel level, JavacNode source) {
+ if (hasConstructor(typeNode, Throwable.class) != MemberExistsResult.NOT_EXISTS) return;
+ JavacTreeMaker maker = typeNode.getTreeMaker();
+ Name causeName = typeNode.toName("cause");
+
+ JCExpression causeDotGetMessage = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(causeName), typeNode.toName("getMessage")), List.<JCExpression>nil());
+ JCExpression msgExpression = maker.Conditional(maker.Binary(CTC_NOT_EQUAL, maker.Ident(causeName), maker.Literal(CTC_BOT, null)), causeDotGetMessage, maker.Literal(CTC_BOT, null));
+
+ List<JCExpression> args = List.<JCExpression>of(msgExpression, maker.Ident(causeName));
+ JCStatement thisCall = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(typeNode.toName("this")), args));
+ JCMethodDecl constr = createConstructor(level, typeNode, false, true, source, List.of(thisCall));
+ injectMethod(typeNode, constr);
+ }
+