use of org.eclipse.jdt.internal.compiler.ast.AllocationExpression in project lombok by rzwitserloot.
the class EclipseJavaUtilSingularizer method createJavaUtilSimpleCreationAndFillStatements.
protected List<Statement> createJavaUtilSimpleCreationAndFillStatements(SingularData data, EclipseNode builderType, boolean mapMode, boolean defineVar, boolean addInitialCapacityArg, boolean nullGuard, String targetType) {
char[] varName = mapMode ? (new String(data.getPluralName()) + "$key").toCharArray() : data.getPluralName();
Statement createStat;
{
// pluralName = new java.util.TargetType(initialCap);
Expression[] constructorArgs = null;
if (addInitialCapacityArg) {
// this.varName.size() < MAX_POWER_OF_2 ? 1 + this.varName.size() + (this.varName.size() - 3) / 3 : Integer.MAX_VALUE;
// lessThanCutOff = this.varName.size() < MAX_POWER_OF_2
Expression lessThanCutoff = new BinaryExpression(getSize(builderType, varName, nullGuard), makeIntLiteral("0x40000000".toCharArray(), null), OperatorIds.LESS);
FieldReference integerMaxValue = new FieldReference("MAX_VALUE".toCharArray(), 0L);
integerMaxValue.receiver = new QualifiedNameReference(TypeConstants.JAVA_LANG_INTEGER, NULL_POSS, 0, 0);
Expression sizeFormulaLeft = new BinaryExpression(makeIntLiteral(new char[] { '1' }, null), getSize(builderType, varName, nullGuard), OperatorIds.PLUS);
Expression sizeFormulaRightLeft = new BinaryExpression(getSize(builderType, varName, nullGuard), makeIntLiteral(new char[] { '3' }, null), OperatorIds.MINUS);
Expression sizeFormulaRight = new BinaryExpression(sizeFormulaRightLeft, makeIntLiteral(new char[] { '3' }, null), OperatorIds.DIVIDE);
Expression sizeFormula = new BinaryExpression(sizeFormulaLeft, sizeFormulaRight, OperatorIds.PLUS);
Expression cond = new ConditionalExpression(lessThanCutoff, sizeFormula, integerMaxValue);
constructorArgs = new Expression[] { cond };
}
TypeReference targetTypeRef = new QualifiedTypeReference(new char[][] { TypeConstants.JAVA, TypeConstants.UTIL, targetType.toCharArray() }, NULL_POSS);
targetTypeRef = addTypeArgs(mapMode ? 2 : 1, false, builderType, targetTypeRef, data.getTypeArgs());
AllocationExpression constructorCall = new AllocationExpression();
constructorCall.type = targetTypeRef;
constructorCall.arguments = constructorArgs;
if (defineVar) {
TypeReference localShadowerType = new QualifiedTypeReference(fromQualifiedName(data.getTargetFqn()), NULL_POSS);
localShadowerType = addTypeArgs(mapMode ? 2 : 1, false, builderType, localShadowerType, data.getTypeArgs());
LocalDeclaration localShadowerDecl = new LocalDeclaration(data.getPluralName(), 0, 0);
localShadowerDecl.type = localShadowerType;
localShadowerDecl.initialization = constructorCall;
createStat = localShadowerDecl;
} else {
createStat = new Assignment(new SingleNameReference(data.getPluralName(), 0L), constructorCall, 0);
}
}
Statement fillStat;
{
if (mapMode) {
// for (int $i = 0; $i < this.pluralname$key.size(); i++) pluralname.put(this.pluralname$key.get($i), this.pluralname$value.get($i));
char[] iVar = new char[] { '$', 'i' };
MessageSend pluralnameDotPut = new MessageSend();
pluralnameDotPut.selector = new char[] { 'p', 'u', 't' };
pluralnameDotPut.receiver = new SingleNameReference(data.getPluralName(), 0L);
FieldReference thisDotKey = new FieldReference(varName, 0L);
thisDotKey.receiver = new ThisReference(0, 0);
FieldReference thisDotValue = new FieldReference((new String(data.getPluralName()) + "$value").toCharArray(), 0L);
thisDotValue.receiver = new ThisReference(0, 0);
MessageSend keyArg = new MessageSend();
keyArg.receiver = thisDotKey;
keyArg.arguments = new Expression[] { new SingleNameReference(iVar, 0L) };
keyArg.selector = new char[] { 'g', 'e', 't' };
MessageSend valueArg = new MessageSend();
valueArg.receiver = thisDotValue;
valueArg.arguments = new Expression[] { new SingleNameReference(iVar, 0L) };
valueArg.selector = new char[] { 'g', 'e', 't' };
pluralnameDotPut.arguments = new Expression[] { keyArg, valueArg };
LocalDeclaration forInit = new LocalDeclaration(iVar, 0, 0);
forInit.type = TypeReference.baseTypeReference(TypeIds.T_int, 0);
forInit.initialization = makeIntLiteral(new char[] { '0' }, null);
Expression checkExpr = new BinaryExpression(new SingleNameReference(iVar, 0L), getSize(builderType, varName, nullGuard), OperatorIds.LESS);
Expression incrementExpr = new PostfixExpression(new SingleNameReference(iVar, 0L), IntLiteral.One, OperatorIds.PLUS, 0);
fillStat = new ForStatement(new Statement[] { forInit }, checkExpr, new Statement[] { incrementExpr }, pluralnameDotPut, true, 0, 0);
} else {
// pluralname.addAll(this.pluralname);
MessageSend pluralnameDotAddAll = new MessageSend();
pluralnameDotAddAll.selector = new char[] { 'a', 'd', 'd', 'A', 'l', 'l' };
pluralnameDotAddAll.receiver = new SingleNameReference(data.getPluralName(), 0L);
FieldReference thisDotPluralname = new FieldReference(varName, 0L);
thisDotPluralname.receiver = new ThisReference(0, 0);
pluralnameDotAddAll.arguments = new Expression[] { thisDotPluralname };
fillStat = pluralnameDotAddAll;
}
if (nullGuard) {
FieldReference thisDotField = new FieldReference(varName, 0L);
thisDotField.receiver = new ThisReference(0, 0);
Expression cond = new EqualExpression(thisDotField, new NullLiteral(0, 0), OperatorIds.NOT_EQUAL);
fillStat = new IfStatement(cond, fillStat, 0, 0);
}
}
Statement unmodifiableStat;
{
// pluralname = Collections.unmodifiableInterfaceType(pluralname);
Expression arg = new SingleNameReference(data.getPluralName(), 0L);
MessageSend invoke = new MessageSend();
invoke.arguments = new Expression[] { arg };
invoke.selector = ("unmodifiable" + data.getTargetSimpleType()).toCharArray();
invoke.receiver = new QualifiedNameReference(JAVA_UTIL_COLLECTIONS, NULL_POSS, 0, 0);
unmodifiableStat = new Assignment(new SingleNameReference(data.getPluralName(), 0L), invoke, 0);
}
return Arrays.asList(createStat, fillStat, unmodifiableStat);
}
use of org.eclipse.jdt.internal.compiler.ast.AllocationExpression 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.AllocationExpression in project lombok by rzwitserloot.
the class HandleWither method createWither.
public MethodDeclaration createWither(TypeDeclaration parent, EclipseNode fieldNode, String name, int modifier, EclipseNode sourceNode, List<Annotation> onMethod, List<Annotation> onParam, boolean makeAbstract) {
ASTNode source = sourceNode.get();
if (name == null)
return null;
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long) pS << 32 | pE;
MethodDeclaration method = new MethodDeclaration(parent.compilationResult);
if (makeAbstract)
modifier = modifier | ClassFileConstants.AccAbstract | ExtraCompilerModifiers.AccSemicolonBody;
method.modifiers = modifier;
method.returnType = cloneSelfType(fieldNode, source);
if (method.returnType == null)
return null;
Annotation[] deprecated = null;
if (isFieldDeprecated(fieldNode)) {
deprecated = new Annotation[] { generateDeprecatedAnnotation(source) };
}
method.annotations = copyAnnotations(source, onMethod.toArray(new Annotation[0]), deprecated);
Argument param = new Argument(field.name, p, copyType(field.type, source), ClassFileConstants.AccFinal);
param.sourceStart = pS;
param.sourceEnd = pE;
method.arguments = new Argument[] { param };
method.selector = name.toCharArray();
method.binding = null;
method.thrownExceptions = null;
method.typeParameters = null;
method.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
Annotation[] nonNulls = findAnnotations(field, NON_NULL_PATTERN);
Annotation[] nullables = findAnnotations(field, NULLABLE_PATTERN);
if (!makeAbstract) {
List<Expression> args = new ArrayList<Expression>();
for (EclipseNode child : fieldNode.up().down()) {
if (child.getKind() != Kind.FIELD)
continue;
FieldDeclaration childDecl = (FieldDeclaration) child.get();
// Skip fields that start with $
if (childDecl.name != null && childDecl.name.length > 0 && childDecl.name[0] == '$')
continue;
long fieldFlags = childDecl.modifiers;
// Skip static fields.
if ((fieldFlags & ClassFileConstants.AccStatic) != 0)
continue;
// Skip initialized final fields.
if (((fieldFlags & ClassFileConstants.AccFinal) != 0) && childDecl.initialization != null)
continue;
if (child.get() == fieldNode.get()) {
args.add(new SingleNameReference(field.name, p));
} else {
args.add(createFieldAccessor(child, FieldAccess.ALWAYS_FIELD, source));
}
}
AllocationExpression constructorCall = new AllocationExpression();
constructorCall.arguments = args.toArray(new Expression[0]);
constructorCall.type = cloneSelfType(fieldNode, source);
Expression identityCheck = new EqualExpression(createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source), new SingleNameReference(field.name, p), OperatorIds.EQUAL_EQUAL);
ThisReference thisRef = new ThisReference(pS, pE);
Expression conditional = new ConditionalExpression(identityCheck, thisRef, constructorCall);
Statement returnStatement = new ReturnStatement(conditional, pS, pE);
method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart;
method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd;
List<Statement> statements = new ArrayList<Statement>(5);
if (nonNulls.length > 0) {
Statement nullCheck = generateNullCheck(field, sourceNode);
if (nullCheck != null)
statements.add(nullCheck);
}
statements.add(returnStatement);
method.statements = statements.toArray(new Statement[0]);
}
param.annotations = copyAnnotations(source, nonNulls, nullables, onParam.toArray(new Annotation[0]));
method.traverse(new SetGeneratedByVisitor(source), parent.scope);
return method;
}
use of org.eclipse.jdt.internal.compiler.ast.AllocationExpression 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 org.eclipse.jdt.internal.compiler.ast.AllocationExpression 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;
}
Aggregations