use of org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement in project lombok by rzwitserloot.
the class HandleSynchronized method handle.
@Override
public void handle(AnnotationValues<Synchronized> annotation, Annotation source, EclipseNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.SYNCHRONIZED_FLAG_USAGE, "@Synchronized");
int p1 = source.sourceStart - 1;
int p2 = source.sourceStart - 2;
long pos = (((long) p1) << 32) | p2;
EclipseNode methodNode = annotationNode.up();
if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof MethodDeclaration)) {
annotationNode.addError("@Synchronized is legal only on methods.");
return;
}
MethodDeclaration method = (MethodDeclaration) methodNode.get();
if (method.isAbstract()) {
annotationNode.addError("@Synchronized is legal only on concrete methods.");
return;
}
char[] lockName = createLockField(annotation, annotationNode, method.isStatic(), true);
if (lockName == null)
return;
if (method.statements == null)
return;
Block block = new Block(0);
setGeneratedBy(block, source);
block.statements = method.statements;
// Positions for in-method generated nodes are special
block.sourceEnd = method.bodyEnd;
block.sourceStart = method.bodyStart;
Expression lockVariable;
if (method.isStatic())
lockVariable = new QualifiedNameReference(new char[][] { methodNode.up().getName().toCharArray(), lockName }, new long[] { pos, pos }, p1, p2);
else {
lockVariable = new FieldReference(lockName, pos);
ThisReference thisReference = new ThisReference(p1, p2);
setGeneratedBy(thisReference, source);
((FieldReference) lockVariable).receiver = thisReference;
}
setGeneratedBy(lockVariable, source);
method.statements = new Statement[] { new SynchronizedStatement(lockVariable, block, 0, 0) };
// Positions for in-method generated nodes are special
method.statements[0].sourceEnd = method.bodyEnd;
method.statements[0].sourceStart = method.bodyStart;
setGeneratedBy(method.statements[0], source);
methodNode.rebuild();
}
use of org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement in project lombok by rzwitserloot.
the class HandleGetter method createLazyGetterBody.
public Statement[] createLazyGetterBody(ASTNode source, EclipseNode fieldNode) {
/*
java.lang.Object value = this.fieldName.get();
if (value == null) {
synchronized (this.fieldName) {
value = this.fieldName.get();
if (value == null) {
final RawValueType actualValue = INITIALIZER_EXPRESSION;
[IF PRIMITIVE]
value = actualValue;
[ELSE]
value = actualValue == null ? this.fieldName : actualValue;
[END IF]
this.fieldName.set(value);
}
}
}
[IF PRIMITIVE]
return (BoxedValueType) value;
[ELSE]
return (BoxedValueType) (value == this.fieldName ? null : value);
[END IF]
*/
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long) pS << 32 | pE;
TypeReference rawComponentType = copyType(field.type, source);
TypeReference boxedComponentType = null;
boolean isPrimitive = false;
if (field.type instanceof SingleTypeReference && !(field.type instanceof ArrayTypeReference)) {
char[][] newType = TYPE_MAP.get(new String(((SingleTypeReference) field.type).token));
if (newType != null) {
boxedComponentType = new QualifiedTypeReference(newType, poss(source, 3));
isPrimitive = true;
}
}
if (boxedComponentType == null)
boxedComponentType = copyType(field.type, source);
boxedComponentType.sourceStart = pS;
boxedComponentType.sourceEnd = boxedComponentType.statementEnd = pE;
Statement[] statements = new Statement[3];
/* java.lang.Object value = this.fieldName.get(); */
{
LocalDeclaration valueDecl = new LocalDeclaration(valueName, pS, pE);
valueDecl.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(source, 3));
valueDecl.type.sourceStart = pS;
valueDecl.type.sourceEnd = valueDecl.type.statementEnd = pE;
MessageSend getter = new MessageSend();
getter.sourceStart = pS;
getter.statementEnd = getter.sourceEnd = pE;
getter.selector = new char[] { 'g', 'e', 't' };
getter.receiver = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source);
valueDecl.initialization = getter;
statements[0] = valueDecl;
}
/*
if (value == null) {
synchronized (this.fieldName) {
value = this.fieldName.get();
if (value == null) {
final ValueType actualValue = INITIALIZER_EXPRESSION;
[IF PRIMITIVE]
value = actualValue;
[ELSE]
value = actualValue == null ? this.fieldName : actualValue;
[END IF]
this.fieldName.set(value);
}
}
}
*/
{
EqualExpression cond = new EqualExpression(new SingleNameReference(valueName, p), new NullLiteral(pS, pE), BinaryExpression.EQUAL_EQUAL);
Block then = new Block(0);
Expression lock = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source);
Block inner = new Block(0);
inner.statements = new Statement[2];
/* value = this.fieldName.get(); */
{
MessageSend getter = new MessageSend();
getter.sourceStart = pS;
getter.sourceEnd = getter.statementEnd = pE;
getter.selector = new char[] { 'g', 'e', 't' };
getter.receiver = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source);
Assignment assign = new Assignment(new SingleNameReference(valueName, p), getter, pE);
assign.sourceStart = pS;
assign.statementEnd = assign.sourceEnd = pE;
inner.statements[0] = assign;
}
/* if (value == null) */
{
EqualExpression innerCond = new EqualExpression(new SingleNameReference(valueName, p), new NullLiteral(pS, pE), BinaryExpression.EQUAL_EQUAL);
innerCond.sourceStart = pS;
innerCond.sourceEnd = innerCond.statementEnd = pE;
Block innerThen = new Block(0);
innerThen.statements = new Statement[3];
/* final ValueType actualValue = INITIALIZER_EXPRESSION */
{
LocalDeclaration actualValueDecl = new LocalDeclaration(actualValueName, pS, pE);
actualValueDecl.type = rawComponentType;
actualValueDecl.type.sourceStart = pS;
actualValueDecl.type.sourceEnd = actualValueDecl.type.statementEnd = pE;
actualValueDecl.initialization = field.initialization;
actualValueDecl.modifiers = ClassFileConstants.AccFinal;
innerThen.statements[0] = actualValueDecl;
}
/* [IF PRIMITIVE] value = actualValue; */
{
if (isPrimitive) {
Assignment innerAssign = new Assignment(new SingleNameReference(valueName, p), new SingleNameReference(actualValueName, p), pE);
innerAssign.sourceStart = pS;
innerAssign.statementEnd = innerAssign.sourceEnd = pE;
innerThen.statements[1] = innerAssign;
}
}
/* [ELSE] value = actualValue == null ? this.fieldName : actualValue; */
{
if (!isPrimitive) {
EqualExpression avIsNull = new EqualExpression(new SingleNameReference(actualValueName, p), new NullLiteral(pS, pE), BinaryExpression.EQUAL_EQUAL);
avIsNull.sourceStart = pS;
avIsNull.sourceEnd = avIsNull.statementEnd = pE;
Expression fieldRef = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source);
ConditionalExpression ternary = new ConditionalExpression(avIsNull, fieldRef, new SingleNameReference(actualValueName, p));
ternary.sourceStart = pS;
ternary.sourceEnd = ternary.statementEnd = pE;
Assignment innerAssign = new Assignment(new SingleNameReference(valueName, p), ternary, pE);
innerAssign.sourceStart = pS;
innerAssign.statementEnd = innerAssign.sourceEnd = pE;
innerThen.statements[1] = innerAssign;
}
}
/* this.fieldName.set(value); */
{
MessageSend setter = new MessageSend();
setter.sourceStart = pS;
setter.sourceEnd = setter.statementEnd = pE;
setter.receiver = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source);
setter.selector = new char[] { 's', 'e', 't' };
setter.arguments = new Expression[] { new SingleNameReference(valueName, p) };
innerThen.statements[2] = setter;
}
IfStatement innerIf = new IfStatement(innerCond, innerThen, pS, pE);
inner.statements[1] = innerIf;
}
SynchronizedStatement sync = new SynchronizedStatement(lock, inner, pS, pE);
then.statements = new Statement[] { sync };
IfStatement ifStatement = new IfStatement(cond, then, pS, pE);
statements[1] = ifStatement;
}
/* [IF PRIMITIVE] return (BoxedValueType)value; */
{
if (isPrimitive) {
CastExpression cast = makeCastExpression(new SingleNameReference(valueName, p), boxedComponentType, source);
statements[2] = new ReturnStatement(cast, pS, pE);
}
}
/* [ELSE] return (BoxedValueType)(value == this.fieldName ? null : value); */
{
if (!isPrimitive) {
EqualExpression vIsThisFieldName = new EqualExpression(new SingleNameReference(valueName, p), createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source), BinaryExpression.EQUAL_EQUAL);
vIsThisFieldName.sourceStart = pS;
vIsThisFieldName.sourceEnd = vIsThisFieldName.statementEnd = pE;
ConditionalExpression ternary = new ConditionalExpression(vIsThisFieldName, new NullLiteral(pS, pE), new SingleNameReference(valueName, p));
ternary.sourceStart = pS;
ternary.sourceEnd = ternary.statementEnd = pE;
ternary.bits |= PARENTHESIZED;
CastExpression cast = makeCastExpression(ternary, boxedComponentType, source);
statements[2] = new ReturnStatement(cast, pS, pE);
}
}
// update the field type and init last
/* private final java.util.concurrent.atomic.AtomicReference<java.lang.Object> fieldName = new java.util.concurrent.atomic.AtomicReference<java.lang.Object>(); */
{
TypeReference innerType = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, poss(source, 3));
TypeReference[][] typeParams = new TypeReference[5][];
typeParams[4] = new TypeReference[] { innerType };
TypeReference type = new ParameterizedQualifiedTypeReference(AR, typeParams, 0, poss(source, 5));
// Some magic here
type.sourceStart = -1;
type.sourceEnd = -2;
field.type = type;
AllocationExpression init = new AllocationExpression();
// Some magic here
init.sourceStart = field.initialization.sourceStart;
init.sourceEnd = init.statementEnd = field.initialization.sourceEnd;
init.type = copyType(type, source);
field.initialization = init;
}
return statements;
}
use of org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement in project lombok by rzwitserloot.
the class HandleNonNull method handle.
@Override
public void handle(AnnotationValues<NonNull> annotation, Annotation ast, EclipseNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.NON_NULL_FLAG_USAGE, "@NonNull");
if (annotationNode.up().getKind() == Kind.FIELD) {
try {
if (isPrimitive(((AbstractVariableDeclaration) annotationNode.up().get()).type)) {
annotationNode.addWarning("@NonNull is meaningless on a primitive.");
}
} catch (Exception ignore) {
}
return;
}
if (annotationNode.up().getKind() != Kind.ARGUMENT)
return;
Argument arg;
AbstractMethodDeclaration declaration;
try {
arg = (Argument) annotationNode.up().get();
declaration = (AbstractMethodDeclaration) annotationNode.up().up().get();
} catch (Exception e) {
return;
}
if (isGenerated(declaration))
return;
if (declaration.isAbstract()) {
// This used to be a warning, but as @NonNull also has a documentary purpose, better to not warn about this. Since 1.16.7
return;
}
// Possibly, if 'declaration instanceof ConstructorDeclaration', fetch declaration.constructorCall, search it for any references to our parameter,
// and if they exist, create a new method in the class: 'private static <T> T lombok$nullCheck(T expr, String msg) {if (expr == null) throw NPE; return expr;}' and
// wrap all references to it in the super/this to a call to this method.
Statement nullCheck = generateNullCheck(arg, annotationNode);
if (nullCheck == null) {
// @NonNull applied to a primitive. Kinda pointless. Let's generate a warning.
annotationNode.addWarning("@NonNull is meaningless on a primitive.");
return;
}
if (declaration.statements == null) {
declaration.statements = new Statement[] { nullCheck };
} else {
char[] expectedName = arg.name;
/* Abort if the null check is already there, delving into try and synchronized statements */
{
Statement[] stats = declaration.statements;
int idx = 0;
while (stats != null && stats.length > idx) {
Statement stat = stats[idx++];
if (stat instanceof TryStatement) {
stats = ((TryStatement) stat).tryBlock.statements;
idx = 0;
continue;
}
if (stat instanceof SynchronizedStatement) {
stats = ((SynchronizedStatement) stat).block.statements;
idx = 0;
continue;
}
char[] varNameOfNullCheck = returnVarNameIfNullCheck(stat);
if (varNameOfNullCheck == null)
break;
if (Arrays.equals(varNameOfNullCheck, expectedName))
return;
}
}
Statement[] newStatements = new Statement[declaration.statements.length + 1];
int skipOver = 0;
for (Statement stat : declaration.statements) {
if (isGenerated(stat) && isNullCheck(stat))
skipOver++;
else
break;
}
System.arraycopy(declaration.statements, 0, newStatements, 0, skipOver);
System.arraycopy(declaration.statements, skipOver, newStatements, skipOver + 1, declaration.statements.length - skipOver);
newStatements[skipOver] = nullCheck;
declaration.statements = newStatements;
}
annotationNode.up().up().rebuild();
}
Aggregations