use of lombok.eclipse.EclipseNode in project lombok by rzwitserloot.
the class HandleCleanup method handle.
public void handle(AnnotationValues<Cleanup> annotation, Annotation ast, EclipseNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.CLEANUP_FLAG_USAGE, "@Cleanup");
String cleanupName = annotation.getInstance().value();
if (cleanupName.length() == 0) {
annotationNode.addError("cleanupName cannot be the empty string.");
return;
}
if (annotationNode.up().getKind() != Kind.LOCAL) {
annotationNode.addError("@Cleanup is legal only on local variable declarations.");
return;
}
LocalDeclaration decl = (LocalDeclaration) annotationNode.up().get();
if (decl.initialization == null) {
annotationNode.addError("@Cleanup variable declarations need to be initialized.");
return;
}
EclipseNode ancestor = annotationNode.up().directUp();
ASTNode blockNode = ancestor.get();
final boolean isSwitch;
final Statement[] statements;
if (blockNode instanceof AbstractMethodDeclaration) {
isSwitch = false;
statements = ((AbstractMethodDeclaration) blockNode).statements;
} else if (blockNode instanceof Block) {
isSwitch = false;
statements = ((Block) blockNode).statements;
} else if (blockNode instanceof SwitchStatement) {
isSwitch = true;
statements = ((SwitchStatement) blockNode).statements;
} else {
annotationNode.addError("@Cleanup is legal only on a local variable declaration inside a block.");
return;
}
if (statements == null) {
annotationNode.addError("LOMBOK BUG: Parent block does not contain any statements.");
return;
}
int start = 0;
for (; start < statements.length; start++) {
if (statements[start] == decl)
break;
}
if (start == statements.length) {
annotationNode.addError("LOMBOK BUG: Can't find this local variable declaration inside its parent.");
return;
}
//We start with try{} *AFTER* the var declaration.
start++;
int end;
if (isSwitch) {
end = start + 1;
for (; end < statements.length; end++) {
if (statements[end] instanceof CaseStatement) {
break;
}
}
} else
end = statements.length;
//At this point:
// start-1 = Local Declaration marked with @Cleanup
// start = first instruction that needs to be wrapped into a try block
// end = last instruction of the scope -OR- last instruction before the next case label in switch statements.
// hence:
// [start, end) = statements for the try block.
Statement[] tryBlock = new Statement[end - start];
System.arraycopy(statements, start, tryBlock, 0, end - start);
//Remove the stuff we just dumped into the tryBlock, and then leave room for the try node.
//Remove room for every statement moved into try block...
int newStatementsLength = statements.length - (end - start);
//But add room for the TryStatement node itself.
newStatementsLength += 1;
Statement[] newStatements = new Statement[newStatementsLength];
//copy all statements before the try block verbatim.
System.arraycopy(statements, 0, newStatements, 0, start);
//For switch statements.
System.arraycopy(statements, end, newStatements, start + 1, statements.length - end);
doAssignmentCheck(annotationNode, tryBlock, decl.name);
TryStatement tryStatement = new TryStatement();
setGeneratedBy(tryStatement, ast);
tryStatement.tryBlock = new Block(0);
tryStatement.tryBlock.statements = tryBlock;
setGeneratedBy(tryStatement.tryBlock, ast);
// Positions for in-method generated nodes are special
int ss = decl.declarationSourceEnd + 1;
int se = ss;
if (tryBlock.length > 0) {
//+1 for the closing semicolon. Yes, there could be spaces. Bummer.
se = tryBlock[tryBlock.length - 1].sourceEnd + 1;
tryStatement.sourceStart = ss;
tryStatement.sourceEnd = se;
tryStatement.tryBlock.sourceStart = ss;
tryStatement.tryBlock.sourceEnd = se;
}
newStatements[start] = tryStatement;
Statement[] finallyBlock = new Statement[1];
MessageSend unsafeClose = new MessageSend();
setGeneratedBy(unsafeClose, ast);
unsafeClose.sourceStart = ast.sourceStart;
unsafeClose.sourceEnd = ast.sourceEnd;
SingleNameReference receiver = new SingleNameReference(decl.name, 0);
setGeneratedBy(receiver, ast);
unsafeClose.receiver = receiver;
long nameSourcePosition = (long) ast.sourceStart << 32 | ast.sourceEnd;
if (ast.memberValuePairs() != null)
for (MemberValuePair pair : ast.memberValuePairs()) {
if (pair.name != null && new String(pair.name).equals("value")) {
nameSourcePosition = (long) pair.value.sourceStart << 32 | pair.value.sourceEnd;
break;
}
}
unsafeClose.nameSourcePosition = nameSourcePosition;
unsafeClose.selector = cleanupName.toCharArray();
int pS = ast.sourceStart, pE = ast.sourceEnd;
long p = (long) pS << 32 | pE;
SingleNameReference varName = new SingleNameReference(decl.name, p);
setGeneratedBy(varName, ast);
NullLiteral nullLiteral = new NullLiteral(pS, pE);
setGeneratedBy(nullLiteral, ast);
MessageSend preventNullAnalysis = preventNullAnalysis(ast, varName);
EqualExpression equalExpression = new EqualExpression(preventNullAnalysis, nullLiteral, OperatorIds.NOT_EQUAL);
equalExpression.sourceStart = pS;
equalExpression.sourceEnd = pE;
setGeneratedBy(equalExpression, ast);
Block closeBlock = new Block(0);
closeBlock.statements = new Statement[1];
closeBlock.statements[0] = unsafeClose;
setGeneratedBy(closeBlock, ast);
IfStatement ifStatement = new IfStatement(equalExpression, closeBlock, 0, 0);
setGeneratedBy(ifStatement, ast);
finallyBlock[0] = ifStatement;
tryStatement.finallyBlock = new Block(0);
// Positions for in-method generated nodes are special
if (!isSwitch) {
tryStatement.finallyBlock.sourceStart = blockNode.sourceEnd;
tryStatement.finallyBlock.sourceEnd = blockNode.sourceEnd;
}
setGeneratedBy(tryStatement.finallyBlock, ast);
tryStatement.finallyBlock.statements = finallyBlock;
tryStatement.catchArguments = null;
tryStatement.catchBlocks = null;
if (blockNode instanceof AbstractMethodDeclaration) {
((AbstractMethodDeclaration) blockNode).statements = newStatements;
} else if (blockNode instanceof Block) {
((Block) blockNode).statements = newStatements;
} else if (blockNode instanceof SwitchStatement) {
((SwitchStatement) blockNode).statements = newStatements;
}
ancestor.rebuild();
}
use of lombok.eclipse.EclipseNode in project lombok by rzwitserloot.
the class HandleConstructor method createStaticConstructor.
public MethodDeclaration createStaticConstructor(AccessLevel level, String name, EclipseNode type, Collection<EclipseNode> fields, ASTNode source) {
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long) pS << 32 | pE;
MethodDeclaration constructor = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
constructor.modifiers = toEclipseModifier(level) | ClassFileConstants.AccStatic;
TypeDeclaration typeDecl = (TypeDeclaration) type.get();
constructor.returnType = EclipseHandlerUtil.namePlusTypeParamsToTypeReference(typeDecl.name, typeDecl.typeParameters, p);
constructor.annotations = null;
constructor.selector = name.toCharArray();
constructor.thrownExceptions = null;
constructor.typeParameters = copyTypeParams(((TypeDeclaration) type.get()).typeParameters, source);
constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart;
constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd;
List<Argument> params = new ArrayList<Argument>();
List<Expression> assigns = new ArrayList<Expression>();
AllocationExpression statement = new AllocationExpression();
statement.sourceStart = pS;
statement.sourceEnd = pE;
statement.type = copyType(constructor.returnType, source);
for (EclipseNode fieldNode : fields) {
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
long fieldPos = (((long) field.sourceStart) << 32) | field.sourceEnd;
SingleNameReference nameRef = new SingleNameReference(field.name, fieldPos);
assigns.add(nameRef);
Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL);
parameter.annotations = copyAnnotations(source, findAnnotations(field, NON_NULL_PATTERN), findAnnotations(field, NULLABLE_PATTERN));
params.add(parameter);
}
statement.arguments = assigns.isEmpty() ? null : assigns.toArray(new Expression[assigns.size()]);
constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[params.size()]);
constructor.statements = new Statement[] { new ReturnStatement(statement, (int) (p >> 32), (int) p) };
constructor.traverse(new SetGeneratedByVisitor(source), typeDecl.scope);
return constructor;
}
use of lombok.eclipse.EclipseNode in project lombok by rzwitserloot.
the class HandleConstructor method generateConstructor.
public void generateConstructor(EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, boolean allToDefault, String staticName, SkipIfConstructorExists skipIfConstructorExists, List<Annotation> onConstructor, EclipseNode sourceNode) {
ASTNode source = sourceNode.get();
boolean staticConstrRequired = staticName != null && !staticName.equals("");
if (skipIfConstructorExists != SkipIfConstructorExists.NO && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS)
return;
if (skipIfConstructorExists != SkipIfConstructorExists.NO) {
for (EclipseNode child : typeNode.down()) {
if (child.getKind() == Kind.ANNOTATION) {
boolean skipGeneration = (annotationTypeMatches(NoArgsConstructor.class, child) || annotationTypeMatches(AllArgsConstructor.class, child) || annotationTypeMatches(RequiredArgsConstructor.class, child));
if (!skipGeneration && skipIfConstructorExists == SkipIfConstructorExists.YES) {
skipGeneration = annotationTypeMatches(Builder.class, child);
}
if (skipGeneration) {
if (staticConstrRequired) {
// @Data has asked us to generate a constructor, but we're going to skip this instruction, as an explicit 'make a constructor' annotation
// will take care of it. However, @Data also wants a specific static name; this will be ignored; the appropriate way to do this is to use
// the 'staticName' parameter of the @XArgsConstructor you've stuck on your type.
// We should warn that we're ignoring @Data's 'staticConstructor' param.
typeNode.addWarning("Ignoring static constructor name: explicit @XxxArgsConstructor annotation present; its `staticName` parameter will be used.", source.sourceStart, source.sourceEnd);
}
return;
}
}
}
}
ConstructorDeclaration constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, allToDefault, sourceNode, onConstructor);
injectMethod(typeNode, constr);
if (staticConstrRequired) {
MethodDeclaration staticConstr = createStaticConstructor(level, staticName, typeNode, allToDefault ? Collections.<EclipseNode>emptyList() : fields, source);
injectMethod(typeNode, staticConstr);
}
}
use of lombok.eclipse.EclipseNode in project lombok by rzwitserloot.
the class EclipseHandlerUtil method createListOfNonExistentFields.
/**
* Given a list of field names and a node referring to a type, finds each name in the list that does not match a field within the type.
*/
public static List<Integer> createListOfNonExistentFields(List<String> list, EclipseNode type, boolean excludeStandard, boolean excludeTransient) {
boolean[] matched = new boolean[list.size()];
for (EclipseNode child : type.down()) {
if (list.isEmpty())
break;
if (child.getKind() != Kind.FIELD)
continue;
if (excludeStandard) {
if ((((FieldDeclaration) child.get()).modifiers & ClassFileConstants.AccStatic) != 0)
continue;
if (child.getName().startsWith("$"))
continue;
}
if (excludeTransient && (((FieldDeclaration) child.get()).modifiers & ClassFileConstants.AccTransient) != 0)
continue;
int idx = list.indexOf(child.getName());
if (idx > -1)
matched[idx] = true;
}
List<Integer> problematic = new ArrayList<Integer>();
for (int i = 0; i < list.size(); i++) {
if (!matched[i])
problematic.add(i);
}
return problematic;
}
use of lombok.eclipse.EclipseNode in project lombok by rzwitserloot.
the class EclipseHandlerUtil method createFieldAccessor.
static Expression createFieldAccessor(EclipseNode field, FieldAccess fieldAccess, ASTNode source) {
int pS = source == null ? 0 : source.sourceStart, pE = source == null ? 0 : source.sourceEnd;
long p = (long) pS << 32 | pE;
boolean lookForGetter = lookForGetter(field, fieldAccess);
GetterMethod getter = lookForGetter ? findGetter(field) : null;
if (getter == null) {
FieldDeclaration fieldDecl = (FieldDeclaration) field.get();
FieldReference ref = new FieldReference(fieldDecl.name, p);
if ((fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0) {
EclipseNode containerNode = field.up();
if (containerNode != null && containerNode.get() instanceof TypeDeclaration) {
ref.receiver = new SingleNameReference(((TypeDeclaration) containerNode.get()).name, p);
} else {
Expression smallRef = new FieldReference(field.getName().toCharArray(), p);
if (source != null)
setGeneratedBy(smallRef, source);
return smallRef;
}
} else {
ref.receiver = new ThisReference(pS, pE);
}
if (source != null) {
setGeneratedBy(ref, source);
setGeneratedBy(ref.receiver, source);
}
return ref;
}
MessageSend call = new MessageSend();
setGeneratedBy(call, source);
call.sourceStart = pS;
call.statementEnd = call.sourceEnd = pE;
call.receiver = new ThisReference(pS, pE);
setGeneratedBy(call.receiver, source);
call.selector = getter.name;
return call;
}
Aggregations