use of lombok.javac.JavacNode in project lombok by rzwitserloot.
the class HandleConstructor method findFields.
public static List<JavacNode> findFields(JavacNode typeNode, boolean nullMarked) {
ListBuffer<JavacNode> fields = new ListBuffer<JavacNode>();
for (JavacNode child : typeNode.down()) {
if (child.getKind() != Kind.FIELD)
continue;
JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
//Skip fields that start with $
if (fieldDecl.name.toString().startsWith("$"))
continue;
long fieldFlags = fieldDecl.mods.flags;
//Skip static fields.
if ((fieldFlags & Flags.STATIC) != 0)
continue;
boolean isFinal = (fieldFlags & Flags.FINAL) != 0;
boolean isNonNull = nullMarked && !findAnnotations(child, NON_NULL_PATTERN).isEmpty();
if ((isFinal || isNonNull) && fieldDecl.init == null)
fields.append(child);
}
return fields.toList();
}
use of lombok.javac.JavacNode in project lombok by rzwitserloot.
the class HandleData method handle.
@Override
public void handle(AnnotationValues<Data> annotation, JCAnnotation ast, JavacNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.DATA_FLAG_USAGE, "@Data");
deleteAnnotationIfNeccessary(annotationNode, Data.class);
JavacNode typeNode = annotationNode.up();
boolean notAClass = !isClass(typeNode);
if (notAClass) {
annotationNode.addError("@Data is only supported on a class.");
return;
}
String staticConstructorName = annotation.getInstance().staticConstructor();
// TODO move this to the end OR move it to the top in eclipse.
new HandleConstructor().generateRequiredArgsConstructor(typeNode, AccessLevel.PUBLIC, staticConstructorName, SkipIfConstructorExists.YES, annotationNode);
new HandleGetter().generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
new HandleSetter().generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
new HandleEqualsAndHashCode().generateEqualsAndHashCodeForType(typeNode, annotationNode);
new HandleToString().generateToStringForType(typeNode, annotationNode);
}
use of lombok.javac.JavacNode in project lombok by rzwitserloot.
the class HandleDelegate method checkConflictOfTypeVarNames.
/**
* There's a rare but problematic case if a delegate method has its own type variables, and the delegated type does too, and the method uses both.
* If for example the delegated type has {@code <E>}, and the method has {@code <T>}, but in our class we have a {@code <T>} at the class level, then we have two different
* type variables both named {@code T}. We detect this situation and error out asking the programmer to rename their type variable.
*
* @throws CantMakeDelegates If there's a conflict. Conflict list is in ex.conflicted.
*/
public void checkConflictOfTypeVarNames(MethodSig sig, JavacNode annotation) throws CantMakeDelegates {
if (sig.elem.getTypeParameters().isEmpty())
return;
Set<String> usedInOurType = new HashSet<String>();
JavacNode enclosingType = annotation;
while (enclosingType != null) {
if (enclosingType.getKind() == Kind.TYPE) {
List<JCTypeParameter> typarams = ((JCClassDecl) enclosingType.get()).typarams;
if (typarams != null)
for (JCTypeParameter param : typarams) {
if (param.name != null)
usedInOurType.add(param.name.toString());
}
}
enclosingType = enclosingType.up();
}
Set<String> usedInMethodSig = new HashSet<String>();
for (TypeParameterElement param : sig.elem.getTypeParameters()) {
usedInMethodSig.add(param.getSimpleName().toString());
}
usedInMethodSig.retainAll(usedInOurType);
if (usedInMethodSig.isEmpty())
return;
// We might be delegating a List<T>, and we are making method <T> toArray(). A conflict is possible.
// But only if the toArray method also uses type vars from its class, otherwise we're only shadowing,
// which is okay as we'll add a @SuppressWarnings.
FindTypeVarScanner scanner = new FindTypeVarScanner();
sig.elem.asType().accept(scanner, null);
Set<String> names = new HashSet<String>(scanner.getTypeVariables());
names.removeAll(usedInMethodSig);
if (!names.isEmpty()) {
// We have a confirmed conflict. We could dig deeper as this may still be a false alarm, but its already an exceedingly rare case.
CantMakeDelegates cmd = new CantMakeDelegates();
cmd.conflicted = usedInMethodSig;
throw cmd;
}
}
use of lombok.javac.JavacNode in project lombok by rzwitserloot.
the class HandleEqualsAndHashCode method createTypeReference.
public JCExpression createTypeReference(JavacNode type, boolean addWildcards) {
java.util.List<String> list = new ArrayList<String>();
list.add(type.getName());
JavacNode tNode = type.up();
while (tNode != null && tNode.getKind() == Kind.TYPE) {
list.add(tNode.getName());
tNode = tNode.up();
}
Collections.reverse(list);
JCClassDecl typeDecl = (JCClassDecl) type.get();
JavacTreeMaker maker = type.getTreeMaker();
JCExpression chain = maker.Ident(type.toName(list.get(0)));
for (int i = 1; i < list.size(); i++) {
chain = maker.Select(chain, type.toName(list.get(i)));
}
if (!addWildcards || typeDecl.typarams.length() == 0)
return chain;
ListBuffer<JCExpression> wildcards = new ListBuffer<JCExpression>();
for (int i = 0; i < typeDecl.typarams.length(); i++) {
wildcards.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null));
}
return maker.TypeApply(chain, wildcards.toList());
}
use of lombok.javac.JavacNode in project lombok by rzwitserloot.
the class HandleEqualsAndHashCode method createEquals.
public JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source, List<JCAnnotation> onParam) {
JavacTreeMaker maker = typeNode.getTreeMaker();
Name oName = typeNode.toName("o");
Name otherName = typeNode.toName("other");
Name thisName = typeNode.toName("this");
JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil());
JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation));
JCExpression objectType = genJavaLangTypeRef(typeNode, "Object");
JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN);
long finalFlag = JavacHandlerUtil.addFinalIfNeeded(0L, typeNode.getContext());
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
final List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(finalFlag | Flags.PARAMETER, onParam), oName, objectType, null));
/* if (o == this) return true; */
{
statements.append(maker.If(maker.Binary(CTC_EQUAL, maker.Ident(oName), maker.Ident(thisName)), returnBool(maker, true), null));
}
/* if (!(o instanceof Outer.Inner.MyType)) return false; */
{
JCUnary notInstanceOf = maker.Unary(CTC_NOT, maker.Parens(maker.TypeTest(maker.Ident(oName), createTypeReference(typeNode, false))));
statements.append(maker.If(notInstanceOf, returnBool(maker, false), null));
}
/* Outer.Inner.MyType<?> other = (Outer.Inner.MyType<?>) o; */
{
if (!fields.isEmpty() || needsCanEqual) {
final JCExpression selfType1 = createTypeReference(typeNode, true), selfType2 = createTypeReference(typeNode, true);
statements.append(maker.VarDef(maker.Modifiers(finalFlag), otherName, selfType1, maker.TypeCast(selfType2, maker.Ident(oName))));
}
}
/* if (!other.canEqual((java.lang.Object) this)) return false; */
{
if (needsCanEqual) {
List<JCExpression> exprNil = List.nil();
JCExpression thisRef = maker.Ident(thisName);
JCExpression castThisRef = maker.TypeCast(genJavaLangTypeRef(typeNode, "Object"), thisRef);
JCExpression equalityCheck = maker.Apply(exprNil, maker.Select(maker.Ident(otherName), typeNode.toName("canEqual")), List.of(castThisRef));
statements.append(maker.If(maker.Unary(CTC_NOT, equalityCheck), returnBool(maker, false), null));
}
}
/* if (!super.equals(o)) return false; */
if (callSuper) {
JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("equals")), List.<JCExpression>of(maker.Ident(oName)));
JCUnary superNotEqual = maker.Unary(CTC_NOT, callToSuper);
statements.append(maker.If(superNotEqual, returnBool(maker, false), null));
}
Name thisDollar = typeNode.toName("this$");
Name otherDollar = typeNode.toName("other$");
for (JavacNode fieldNode : fields) {
JCExpression fType = getFieldType(fieldNode, fieldAccess);
JCExpression thisFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess);
JCExpression otherFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess, maker.Ident(otherName));
if (fType instanceof JCPrimitiveTypeTree) {
switch(((JCPrimitiveTypeTree) fType).getPrimitiveTypeKind()) {
case FLOAT:
/* if (Float.compare(this.fieldName, other.fieldName) != 0) return false; */
statements.append(generateCompareFloatOrDouble(thisFieldAccessor, otherFieldAccessor, maker, typeNode, false));
break;
case DOUBLE:
/* if (Double.compare(this.fieldName, other.fieldName) != 0) return false; */
statements.append(generateCompareFloatOrDouble(thisFieldAccessor, otherFieldAccessor, maker, typeNode, true));
break;
default:
/* if (this.fieldName != other.fieldName) return false; */
statements.append(maker.If(maker.Binary(CTC_NOT_EQUAL, thisFieldAccessor, otherFieldAccessor), returnBool(maker, false), null));
break;
}
} else if (fType instanceof JCArrayTypeTree) {
/* if (!java.util.Arrays.deepEquals(this.fieldName, other.fieldName)) return false; //use equals for primitive arrays. */
boolean multiDim = ((JCArrayTypeTree) fType).elemtype instanceof JCArrayTypeTree;
boolean primitiveArray = ((JCArrayTypeTree) fType).elemtype instanceof JCPrimitiveTypeTree;
boolean useDeepEquals = multiDim || !primitiveArray;
JCExpression eqMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepEquals ? "deepEquals" : "equals");
List<JCExpression> args = List.of(thisFieldAccessor, otherFieldAccessor);
statements.append(maker.If(maker.Unary(CTC_NOT, maker.Apply(List.<JCExpression>nil(), eqMethod, args)), returnBool(maker, false), null));
} 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; */
Name fieldName = ((JCVariableDecl) fieldNode.get()).name;
Name thisDollarFieldName = thisDollar.append(fieldName);
Name otherDollarFieldName = otherDollar.append(fieldName);
statements.append(maker.VarDef(maker.Modifiers(finalFlag), thisDollarFieldName, genJavaLangTypeRef(typeNode, "Object"), thisFieldAccessor));
statements.append(maker.VarDef(maker.Modifiers(finalFlag), otherDollarFieldName, genJavaLangTypeRef(typeNode, "Object"), otherFieldAccessor));
JCExpression thisEqualsNull = maker.Binary(CTC_EQUAL, maker.Ident(thisDollarFieldName), maker.Literal(CTC_BOT, null));
JCExpression otherNotEqualsNull = maker.Binary(CTC_NOT_EQUAL, maker.Ident(otherDollarFieldName), maker.Literal(CTC_BOT, null));
JCExpression thisEqualsThat = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(thisDollarFieldName), typeNode.toName("equals")), List.<JCExpression>of(maker.Ident(otherDollarFieldName)));
JCExpression fieldsAreNotEqual = maker.Conditional(thisEqualsNull, otherNotEqualsNull, maker.Unary(CTC_NOT, thisEqualsThat));
statements.append(maker.If(fieldsAreNotEqual, returnBool(maker, false), null));
}
}
/* return true; */
{
statements.append(returnBool(maker, true));
}
JCBlock body = maker.Block(0, statements.toList());
return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("equals"), returnType, List.<JCTypeParameter>nil(), params, List.<JCExpression>nil(), body, null), source, typeNode.getContext());
}
Aggregations