use of org.eclipse.jdt.internal.compiler.ast.ASTNode 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 org.eclipse.jdt.internal.compiler.ast.ASTNode 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 org.eclipse.jdt.internal.compiler.ast.ASTNode in project lombok by rzwitserloot.
the class EclipseHandlerUtil method generateNullCheck.
/**
* Generates a new statement that checks if the given variable is null, and if so, throws a specified exception with the
* variable name as message.
*
* @param exName The name of the exception to throw; normally {@code java.lang.NullPointerException}.
*/
public static Statement generateNullCheck(AbstractVariableDeclaration variable, EclipseNode sourceNode) {
NullCheckExceptionType exceptionType = sourceNode.getAst().readConfiguration(ConfigurationKeys.NON_NULL_EXCEPTION_TYPE);
if (exceptionType == null)
exceptionType = NullCheckExceptionType.NULL_POINTER_EXCEPTION;
ASTNode source = sourceNode.get();
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long) pS << 32 | pE;
if (isPrimitive(variable.type))
return null;
AllocationExpression exception = new AllocationExpression();
setGeneratedBy(exception, source);
int partCount = 1;
String exceptionTypeStr = exceptionType.getExceptionType();
for (int i = 0; i < exceptionTypeStr.length(); i++) if (exceptionTypeStr.charAt(i) == '.')
partCount++;
long[] ps = new long[partCount];
Arrays.fill(ps, 0L);
exception.type = new QualifiedTypeReference(fromQualifiedName(exceptionTypeStr), ps);
setGeneratedBy(exception.type, source);
exception.arguments = new Expression[] { new StringLiteral(exceptionType.toExceptionMessage(new String(variable.name)).toCharArray(), pS, pE, 0) };
setGeneratedBy(exception.arguments[0], source);
ThrowStatement throwStatement = new ThrowStatement(exception, pS, pE);
setGeneratedBy(throwStatement, source);
SingleNameReference varName = new SingleNameReference(variable.name, p);
setGeneratedBy(varName, source);
NullLiteral nullLiteral = new NullLiteral(pS, pE);
setGeneratedBy(nullLiteral, source);
EqualExpression equalExpression = new EqualExpression(varName, nullLiteral, OperatorIds.EQUAL_EQUAL);
equalExpression.sourceStart = pS;
equalExpression.statementEnd = equalExpression.sourceEnd = pE;
setGeneratedBy(equalExpression, source);
Block throwBlock = new Block(0);
throwBlock.statements = new Statement[] { throwStatement };
throwBlock.sourceStart = pS;
throwBlock.sourceEnd = pE;
setGeneratedBy(throwBlock, source);
IfStatement ifStatement = new IfStatement(equalExpression, throwBlock, 0, 0);
setGeneratedBy(ifStatement, source);
return ifStatement;
}
use of org.eclipse.jdt.internal.compiler.ast.ASTNode in project lombok by rzwitserloot.
the class HandleConstructor method createConstructor.
public static ConstructorDeclaration createConstructor(AccessLevel level, EclipseNode type, Collection<EclipseNode> fields, boolean allToDefault, EclipseNode sourceNode, List<Annotation> onConstructor) {
ASTNode source = sourceNode.get();
TypeDeclaration typeDeclaration = ((TypeDeclaration) type.get());
long p = (long) source.sourceStart << 32 | source.sourceEnd;
boolean isEnum = (((TypeDeclaration) type.get()).modifiers & ClassFileConstants.AccEnum) != 0;
if (isEnum)
level = AccessLevel.PRIVATE;
boolean suppressConstructorProperties;
if (fields.isEmpty()) {
suppressConstructorProperties = false;
} else {
suppressConstructorProperties = Boolean.TRUE.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.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
constructor.constructorCall.sourceStart = source.sourceStart;
constructor.constructorCall.sourceEnd = source.sourceEnd;
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<Statement> assigns = new ArrayList<Statement>();
List<Statement> nullChecks = new ArrayList<Statement>();
for (EclipseNode fieldNode : fields) {
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
char[] rawName = field.name;
char[] fieldName = removePrefixFromField(fieldNode);
FieldReference thisX = new FieldReference(rawName, p);
int s = (int) (p >> 32);
int e = (int) p;
thisX.receiver = new ThisReference(s, e);
Expression assignmentExpr = allToDefault ? getDefaultExpr(field.type, s, e) : new SingleNameReference(fieldName, p);
Assignment assignment = new Assignment(thisX, assignmentExpr, (int) p);
assignment.sourceStart = (int) (p >> 32);
assignment.sourceEnd = assignment.statementEnd = (int) (p >> 32);
assigns.add(assignment);
if (!allToDefault) {
long fieldPos = (((long) field.sourceStart) << 32) | field.sourceEnd;
Argument parameter = new Argument(fieldName, fieldPos, copyType(field.type, source), Modifier.FINAL);
Annotation[] nonNulls = findAnnotations(field, NON_NULL_PATTERN);
Annotation[] nullables = findAnnotations(field, NULLABLE_PATTERN);
if (nonNulls.length != 0) {
Statement nullCheck = generateNullCheck(field, sourceNode);
if (nullCheck != null)
nullChecks.add(nullCheck);
}
parameter.annotations = copyAnnotations(source, nonNulls, nullables);
params.add(parameter);
}
}
nullChecks.addAll(assigns);
constructor.statements = nullChecks.isEmpty() ? null : nullChecks.toArray(new Statement[nullChecks.size()]);
constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[params.size()]);
/* Generate annotations that must be put on the generated method, and attach them. */
{
Annotation[] constructorProperties = null;
if (!allToDefault && !suppressConstructorProperties && level != AccessLevel.PRIVATE && level != AccessLevel.PACKAGE && !isLocalType(type)) {
constructorProperties = createConstructorProperties(source, fields);
}
constructor.annotations = copyAnnotations(source, onConstructor.toArray(new Annotation[0]), constructorProperties);
}
constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope);
return constructor;
}
use of org.eclipse.jdt.internal.compiler.ast.ASTNode in project lombok by rzwitserloot.
the class HandleUtilityClass method createPrivateDefaultConstructor.
private void createPrivateDefaultConstructor(EclipseNode typeNode, EclipseNode sourceNode) {
ASTNode source = sourceNode.get();
TypeDeclaration typeDeclaration = ((TypeDeclaration) typeNode.get());
long p = (long) source.sourceStart << 32 | source.sourceEnd;
ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) typeNode.top().get()).compilationResult);
constructor.modifiers = ClassFileConstants.AccPrivate;
constructor.selector = typeDeclaration.name;
constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
constructor.constructorCall.sourceStart = source.sourceStart;
constructor.constructorCall.sourceEnd = source.sourceEnd;
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;
AllocationExpression exception = new AllocationExpression();
setGeneratedBy(exception, source);
long[] ps = new long[JAVA_LANG_UNSUPPORTED_OPERATION_EXCEPTION.length];
Arrays.fill(ps, p);
exception.type = new QualifiedTypeReference(JAVA_LANG_UNSUPPORTED_OPERATION_EXCEPTION, ps);
setGeneratedBy(exception.type, source);
exception.arguments = new Expression[] { new StringLiteral(UNSUPPORTED_MESSAGE, source.sourceStart, source.sourceEnd, 0) };
setGeneratedBy(exception.arguments[0], source);
ThrowStatement throwStatement = new ThrowStatement(exception, source.sourceStart, source.sourceEnd);
setGeneratedBy(throwStatement, source);
constructor.statements = new Statement[] { throwStatement };
injectMethod(typeNode, constructor);
}
Aggregations