mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-14 10:18:46 +00:00
@StandardException feature working draft
* annotation with javac and Eclipse handlers * single test file
This commit is contained in:
1 parent
30a2921e63
commit
63ea3db6b7
7 files changed
+554
-1
No files matched your search
@@ -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.") {};
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface StandardException {
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2020 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.StandardException;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.eclipse.Eclipse;
|
||||
import lombok.eclipse.EclipseAnnotationHandler;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
import lombok.eclipse.handlers.EclipseHandlerUtil.*;
|
||||
import org.eclipse.jdt.internal.compiler.ast.*;
|
||||
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
|
||||
import org.mangosdk.spi.ProviderFor;
|
||||
|
||||
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.Eclipse.pos;
|
||||
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
|
||||
|
||||
@ProviderFor(EclipseAnnotationHandler.class)
|
||||
public class HandleStandardException extends EclipseAnnotationHandler<StandardException> {
|
||||
private static final String NAME = StandardException.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
public void handle(AnnotationValues<StandardException> annotation, Annotation ast, EclipseNode annotationNode) {
|
||||
handleFlagUsage(annotationNode, ConfigurationKeys.STANDARD_EXCEPTION_FLAG_USAGE, "@StandardException");
|
||||
|
||||
EclipseNode typeNode = annotationNode.up();
|
||||
if (!checkLegality(typeNode, annotationNode)) return;
|
||||
|
||||
SuperParameter message = new SuperParameter("message", new SingleTypeReference("String".toCharArray(), pos(typeNode.get())));
|
||||
SuperParameter cause = new SuperParameter("cause", new SingleTypeReference("Throwable".toCharArray(), pos(typeNode.get())));
|
||||
|
||||
boolean skip = true;
|
||||
generateConstructor(
|
||||
typeNode, AccessLevel.PUBLIC, Collections.<SuperParameter>emptyList(), skip, annotationNode);
|
||||
generateConstructor(
|
||||
typeNode, AccessLevel.PUBLIC, Collections.singletonList(message), skip, annotationNode);
|
||||
generateConstructor(
|
||||
typeNode, AccessLevel.PUBLIC, Collections.singletonList(cause), skip, annotationNode);
|
||||
generateConstructor(
|
||||
typeNode, AccessLevel.PUBLIC, Arrays.asList(message, cause), skip, annotationNode);
|
||||
}
|
||||
|
||||
private static boolean checkLegality(EclipseNode typeNode, EclipseNode errorNode) {
|
||||
TypeDeclaration typeDecl = null;
|
||||
if (typeNode.get() instanceof TypeDeclaration) typeDecl = (TypeDeclaration) typeNode.get();
|
||||
int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
|
||||
boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0;
|
||||
|
||||
if (typeDecl == null || notAClass) {
|
||||
errorNode.addError(HandleStandardException.NAME + " is only supported on a class or an enum.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void generateConstructor(
|
||||
EclipseNode typeNode, AccessLevel level, List<SuperParameter> parameters, boolean skipIfConstructorExists,
|
||||
EclipseNode sourceNode) {
|
||||
|
||||
generate(typeNode, level, parameters, skipIfConstructorExists, sourceNode);
|
||||
}
|
||||
|
||||
public void generate(
|
||||
EclipseNode typeNode, AccessLevel level, List<SuperParameter> parameters, boolean skipIfConstructorExists,
|
||||
EclipseNode sourceNode) {
|
||||
if (!(skipIfConstructorExists
|
||||
&& constructorExists(typeNode, parameters) != MemberExistsResult.NOT_EXISTS)) {
|
||||
ConstructorDeclaration constr = createConstructor(level, typeNode, parameters, sourceNode);
|
||||
injectMethod(typeNode, constr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a constructor with the provided parameters exists under the type node.
|
||||
*/
|
||||
public static MemberExistsResult constructorExists(EclipseNode node, List<SuperParameter> parameters) {
|
||||
node = upToTypeNode(node);
|
||||
SuperParameter[] parameterArray = parameters.toArray(new SuperParameter[0]);
|
||||
|
||||
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 (!paramsMatch(node, def.arguments, parameterArray)) continue;
|
||||
return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MemberExistsResult.NOT_EXISTS;
|
||||
}
|
||||
|
||||
private static boolean paramsMatch(EclipseNode node, Argument[] arguments, SuperParameter[] parameters) {
|
||||
if (arguments == null) {
|
||||
return parameters.length == 0;
|
||||
} else if (arguments.length != parameters.length) {
|
||||
return false;
|
||||
} else {
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
String fieldTypeName = Eclipse.toQualifiedName(parameters[i].type.getTypeName());
|
||||
String argTypeName = Eclipse.toQualifiedName(arguments[i].type.getTypeName());
|
||||
|
||||
if (!typeNamesMatch(node, fieldTypeName, argTypeName))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean typeNamesMatch(EclipseNode node, String a, String b) {
|
||||
boolean isFqn = node.getImportListAsTypeResolver().typeMatches(node, a, b);
|
||||
boolean reverseIsFqn = node.getImportListAsTypeResolver().typeMatches(node, b, a);
|
||||
return isFqn || reverseIsFqn;
|
||||
}
|
||||
|
||||
private static final char[][] JAVA_BEANS_CONSTRUCTORPROPERTIES = new char[][] { "java".toCharArray(), "beans".toCharArray(), "ConstructorProperties".toCharArray() };
|
||||
public static Annotation[] createConstructorProperties(ASTNode source, Collection<SuperParameter> fields) {
|
||||
if (fields.isEmpty()) 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[fields.size()];
|
||||
|
||||
int ctr = 0;
|
||||
for (SuperParameter field : fields) {
|
||||
char[] fieldName = field.name.toCharArray();
|
||||
fieldNames.expressions[ctr] = new StringLiteral(fieldName, 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 type, Collection<SuperParameter> parameters, EclipseNode sourceNode) {
|
||||
|
||||
ASTNode source = sourceNode.get();
|
||||
TypeDeclaration typeDeclaration = ((TypeDeclaration) type.get());
|
||||
|
||||
boolean isEnum = (((TypeDeclaration) type.get()).modifiers & ClassFileConstants.AccEnum) != 0;
|
||||
|
||||
if (isEnum) level = AccessLevel.PRIVATE;
|
||||
|
||||
boolean addConstructorProperties;
|
||||
if (parameters.isEmpty()) {
|
||||
addConstructorProperties = false;
|
||||
} else {
|
||||
Boolean v = type.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_ADD_CONSTRUCTOR_PROPERTIES);
|
||||
addConstructorProperties = v != null ? v.booleanValue() :
|
||||
Boolean.FALSE.equals(type.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_SUPPRESS_CONSTRUCTOR_PROPERTIES));
|
||||
}
|
||||
|
||||
ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) type.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 = source.sourceStart;
|
||||
constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd;
|
||||
constructor.arguments = null;
|
||||
|
||||
List<Argument> params = new ArrayList<Argument>();
|
||||
List<Expression> superArgs = new ArrayList<Expression>();
|
||||
|
||||
for (SuperParameter fieldNode : parameters) {
|
||||
char[] fieldName = fieldNode.name.toCharArray();
|
||||
long fieldPos = (((long) type.get().sourceStart) << 32) | type.get().sourceEnd;
|
||||
Argument parameter = new Argument(fieldName, fieldPos, copyType(fieldNode.type, source), Modifier.FINAL);
|
||||
params.add(parameter);
|
||||
superArgs.add(new SingleNameReference(fieldName, 0));
|
||||
}
|
||||
|
||||
// Super constructor call
|
||||
constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.Super);
|
||||
constructor.constructorCall.arguments = superArgs.toArray(new Expression[0]);
|
||||
constructor.constructorCall.sourceStart = source.sourceStart;
|
||||
constructor.constructorCall.sourceEnd = source.sourceEnd;
|
||||
|
||||
constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[0]);
|
||||
|
||||
Annotation[] constructorProperties = null;
|
||||
if (addConstructorProperties && !isLocalType(type)) constructorProperties = createConstructorProperties(source, parameters);
|
||||
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;
|
||||
}
|
||||
|
||||
private static class SuperParameter {
|
||||
private final String name;
|
||||
private final TypeReference type;
|
||||
|
||||
private SuperParameter(String name, TypeReference type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2019 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* 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.code.Type;
|
||||
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.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 org.mangosdk.spi.ProviderFor;
|
||||
|
||||
import static lombok.core.handlers.HandlerUtil.handleFlagUsage;
|
||||
import static lombok.javac.Javac.CTC_VOID;
|
||||
import static lombok.javac.handlers.JavacHandlerUtil.*;
|
||||
|
||||
@ProviderFor(JavacAnnotationHandler.class)
|
||||
public class HandleStandardException extends JavacAnnotationHandler<StandardException> {
|
||||
private static final String NAME = StandardException.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
public void handle(AnnotationValues<StandardException> annotation, JCAnnotation ast, JavacNode annotationNode) {
|
||||
handleFlagUsage(annotationNode, ConfigurationKeys.STANDARD_EXCEPTION_FLAG_USAGE, "@StandardException");
|
||||
deleteAnnotationIfNeccessary(annotationNode, StandardException.class);
|
||||
JavacNode typeNode = annotationNode.up();
|
||||
if (!checkLegality(typeNode, annotationNode)) return;
|
||||
|
||||
SuperParameter messageField = new SuperParameter("message", typeNode.getSymbolTable().stringType);
|
||||
SuperParameter causeField = new SuperParameter("cause", typeNode.getSymbolTable().throwableType);
|
||||
|
||||
boolean skip = true;
|
||||
generateConstructor(typeNode, AccessLevel.PUBLIC, List.<SuperParameter>nil(), skip, annotationNode);
|
||||
generateConstructor(typeNode, AccessLevel.PUBLIC, List.of(messageField), skip, annotationNode);
|
||||
generateConstructor(typeNode, AccessLevel.PUBLIC, List.of(causeField), skip, annotationNode);
|
||||
generateConstructor(typeNode, AccessLevel.PUBLIC, List.of(messageField, causeField), skip, annotationNode);
|
||||
}
|
||||
|
||||
private static boolean checkLegality(JavacNode typeNode, JavacNode errorNode) {
|
||||
JCClassDecl typeDecl = null;
|
||||
if (typeNode.get() instanceof JCClassDecl) typeDecl = (JCClassDecl) typeNode.get();
|
||||
long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags;
|
||||
boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION)) != 0;
|
||||
|
||||
if (typeDecl == null || notAClass) {
|
||||
errorNode.addError(NAME + " is only supported on a class or an enum.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void generateConstructor(JavacNode typeNode, AccessLevel level, List<SuperParameter> fields,
|
||||
boolean skipIfConstructorExists, JavacNode source) {
|
||||
generate(typeNode, level, fields, skipIfConstructorExists, source);
|
||||
}
|
||||
|
||||
private void generate(JavacNode typeNode, AccessLevel level, List<SuperParameter> fields, boolean skipIfConstructorExists,
|
||||
JavacNode source) {
|
||||
ListBuffer<Type> argTypes = new ListBuffer<Type>();
|
||||
for (SuperParameter field : fields) {
|
||||
Type mirror = field.type;
|
||||
if (mirror == null) {
|
||||
argTypes = null;
|
||||
break;
|
||||
}
|
||||
argTypes.append(mirror);
|
||||
}
|
||||
List<Type> argTypes_ = argTypes == null ? null : argTypes.toList();
|
||||
|
||||
if (!(skipIfConstructorExists && constructorExists(typeNode, fields) != MemberExistsResult.NOT_EXISTS)) {
|
||||
JCMethodDecl constr = createConstructor(level, typeNode, fields, source);
|
||||
injectMethod(typeNode, constr, argTypes_, Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID));
|
||||
}
|
||||
}
|
||||
|
||||
public static MemberExistsResult constructorExists(JavacNode node, List<SuperParameter> parameters) {
|
||||
node = upToTypeNode(node);
|
||||
|
||||
if (node != null && node.get() instanceof JCClassDecl) {
|
||||
for (JCTree def : ((JCClassDecl) node.get()).defs) {
|
||||
if (def instanceof JCMethodDecl) {
|
||||
JCMethodDecl md = (JCMethodDecl) def;
|
||||
if (md.name.contentEquals("<init>") && (md.mods.flags & Flags.GENERATEDCONSTR) == 0) {
|
||||
if (!paramsMatch(md.params, parameters)) continue;
|
||||
return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MemberExistsResult.NOT_EXISTS;
|
||||
}
|
||||
|
||||
private static boolean paramsMatch(List<JCVariableDecl> params, List<SuperParameter> superParams) {
|
||||
if (params == null) {
|
||||
return superParams.size() == 0;
|
||||
} else if (params.size() != superParams.size()) {
|
||||
return false;
|
||||
} else {
|
||||
for (int i = 0; i < superParams.size(); i++) {
|
||||
SuperParameter field = superParams.get(i);
|
||||
JCVariableDecl param = params.get(i);
|
||||
if (!param.getType().type.equals(field.type))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void addConstructorProperties(JCModifiers mods, JavacNode node, List<SuperParameter> fields) {
|
||||
if (fields.isEmpty()) return;
|
||||
JavacTreeMaker maker = node.getTreeMaker();
|
||||
JCExpression constructorPropertiesType = chainDots(node, "java", "beans", "ConstructorProperties");
|
||||
ListBuffer<JCExpression> fieldNames = new ListBuffer<JCExpression>();
|
||||
for (SuperParameter field : fields) {
|
||||
Name fieldName = node.toName(field.name);
|
||||
fieldNames.append(maker.Literal(fieldName.toString()));
|
||||
}
|
||||
JCExpression fieldNamesArray = maker.NewArray(null, List.<JCExpression>nil(), fieldNames.toList());
|
||||
JCAnnotation annotation = maker.Annotation(constructorPropertiesType, List.of(fieldNamesArray));
|
||||
mods.annotations = mods.annotations.append(annotation);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") public static JCMethodDecl createConstructor(AccessLevel level, JavacNode typeNode,
|
||||
List<SuperParameter> fieldsToParam, JavacNode source) {
|
||||
JavacTreeMaker maker = typeNode.getTreeMaker();
|
||||
|
||||
boolean isEnum = (((JCClassDecl) typeNode.get()).mods.flags & Flags.ENUM) != 0;
|
||||
if (isEnum) level = AccessLevel.PRIVATE;
|
||||
|
||||
boolean addConstructorProperties;
|
||||
|
||||
if (fieldsToParam.isEmpty()) {
|
||||
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));
|
||||
}
|
||||
|
||||
ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
|
||||
ListBuffer<JCExpression> superArgs = new ListBuffer<JCExpression>();
|
||||
|
||||
for (SuperParameter fieldNode : fieldsToParam) {
|
||||
Name fieldName = source.toName(fieldNode.name);
|
||||
long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext());
|
||||
JCExpression pType = maker.getUnderlyingTreeMaker().Ident(fieldNode.type.tsym);
|
||||
JCVariableDecl param = maker.VarDef(maker.Modifiers(flags), fieldName, pType, null);
|
||||
params.append(param);
|
||||
superArgs.append(maker.Ident(fieldName));
|
||||
}
|
||||
|
||||
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
|
||||
JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(),
|
||||
maker.Ident(typeNode.toName("super")),
|
||||
superArgs.toList());
|
||||
statements.add(maker.Exec(callToSuper));
|
||||
|
||||
JCModifiers mods = maker.Modifiers(toJavacModifier(level), List.<JCAnnotation>nil());
|
||||
if (addConstructorProperties && !isLocalType(typeNode) && LombokOptionsFactory.getDelombokOptions(typeNode.getContext()).getFormatPreferences().generateConstructorProperties()) {
|
||||
addConstructorProperties(mods, typeNode, fieldsToParam);
|
||||
}
|
||||
return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("<init>"),
|
||||
null, List.<JCTypeParameter>nil(), params.toList(), List.<JCExpression>nil(),
|
||||
maker.Block(0L, statements.toList()), null), source.get(), typeNode.getContext());
|
||||
}
|
||||
|
||||
public static boolean isLocalType(JavacNode type) {
|
||||
Kind kind = type.up().getKind();
|
||||
if (kind == Kind.COMPILATION_UNIT) return false;
|
||||
if (kind == Kind.TYPE) return isLocalType(type.up());
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class SuperParameter {
|
||||
private final String name;
|
||||
private final Type type;
|
||||
|
||||
private SuperParameter(String name, Type type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,9 @@ public class Symtab {
|
||||
public static Symtab instance(Context context) {return null;}
|
||||
public Type unknownType;
|
||||
public TypeSymbol noSymbol;
|
||||
|
||||
public Type stringType;
|
||||
public Type throwableType;
|
||||
|
||||
// JDK 9
|
||||
public ModuleSymbol unnamedModule;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
class EmptyException extends Exception {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public EmptyException() {
|
||||
}
|
||||
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public EmptyException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public EmptyException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public EmptyException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
class NoArgsException extends Exception {
|
||||
public NoArgsException() {
|
||||
}
|
||||
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public NoArgsException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public NoArgsException(final Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public NoArgsException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
@lombok.StandardException class EmptyException extends Exception {
|
||||
}
|
||||
@lombok.StandardException class NoArgsException extends Exception {
|
||||
public NoArgsException() {
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user