Introduce an event consumer in trace references
This refactors the UseCollector in TraceReferences so that all emitted events go through an event consumer.
This makes it straight-forward to use different event consumers for different parts of the tracing.
Change-Id: I0c10da0c4551dbd2c5747957bfc4bcbaa05da5b1
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialUseCollector.java b/src/main/java/com/android/tools/r8/partial/R8PartialUseCollector.java
index be87a90..0a1dbb4 100644
--- a/src/main/java/com/android/tools/r8/partial/R8PartialUseCollector.java
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialUseCollector.java
@@ -81,22 +81,22 @@
protected abstract void keep(Definition definition, DefinitionContext referencedFrom);
@Override
- protected void notifyPresentClass(DexClass clazz, DefinitionContext referencedFrom) {
+ public void notifyPresentClass(DexClass clazz, DefinitionContext referencedFrom) {
notifyPresentItem(clazz, referencedFrom);
}
@Override
- protected void notifyPresentField(DexClassAndField field, DefinitionContext referencedFrom) {
+ public void notifyPresentField(DexClassAndField field, DefinitionContext referencedFrom) {
notifyPresentItem(field, referencedFrom);
}
@Override
- protected void notifyPresentMethod(DexClassAndMethod method, DefinitionContext referencedFrom) {
+ public void notifyPresentMethod(DexClassAndMethod method, DefinitionContext referencedFrom) {
notifyPresentItem(method, referencedFrom);
}
@Override
- protected void notifyPresentMethod(
+ public void notifyPresentMethod(
DexClassAndMethod method, DefinitionContext referencedFrom, DexMethod reference) {
notifyPresentItem(method, referencedFrom);
}
@@ -108,7 +108,7 @@
}
@Override
- protected void notifyPackageOf(Definition definition) {
+ public void notifyPackageOf(Definition definition) {
packagesToKeep.add(definition.getContextType().getPackageName());
}
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 990c181..644fd53 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -297,7 +297,7 @@
}
@Override
- protected void notifyMissingClass(DexType type, DefinitionContext referencedFrom) {
+ public void notifyMissingClass(DexType type, DefinitionContext referencedFrom) {
assert recordMissingClassWhenAssertionsEnabled(type);
}
diff --git a/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java b/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
index 9c22698..191dd0e 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
@@ -65,7 +65,7 @@
// The graph lens is intentionally only made accessible to the MethodUseCollector, since the
// graph lens should only be applied to the code.
-public class UseCollector {
+public class UseCollector implements UseCollectorEventConsumer {
protected final AppView<? extends AppInfoWithClassHierarchy> appView;
private final DexItemFactory factory;
@@ -92,6 +92,10 @@
this.dalvikAnnotationCodegenPrefix = factory.createString("Ldalvik/annotation/codegen/");
}
+ private UseCollectorEventConsumer getDefaultEventConsumer() {
+ return this;
+ }
+
public void traceClasses(Collection<DexProgramClass> classes) {
for (DexProgramClass clazz : classes) {
traceClass(clazz);
@@ -106,19 +110,23 @@
public void traceClass(DexProgramClass clazz) {
DefinitionContext classContext = DefinitionContextUtils.create(clazz);
- clazz.forEachImmediateSupertype(supertype -> registerSuperType(clazz, supertype, classContext));
- clazz.forEachProgramField(this::registerField);
- clazz.forEachProgramMethod(this::registerMethod);
+ clazz.forEachImmediateSupertype(
+ supertype -> registerSuperType(clazz, supertype, classContext, getDefaultEventConsumer()));
+ clazz.forEachProgramField(field -> registerField(field, getDefaultEventConsumer()));
+ clazz.forEachProgramMethod(method -> registerMethod(method, getDefaultEventConsumer()));
for (DexAnnotation annotation : clazz.annotations().getAnnotations()) {
- registerAnnotation(annotation, clazz, classContext);
+ registerAnnotation(annotation, clazz, classContext, getDefaultEventConsumer());
}
- traceKotlinMetadata(clazz, classContext);
- traceSignature(clazz, classContext);
+ traceKotlinMetadata(clazz, classContext, getDefaultEventConsumer());
+ traceSignature(clazz, classContext, getDefaultEventConsumer());
}
- private void traceKotlinMetadata(DexProgramClass clazz, DefinitionContext classContext) {
+ private void traceKotlinMetadata(
+ DexProgramClass clazz,
+ DefinitionContext classContext,
+ UseCollectorEventConsumer eventConsumer) {
if (parseKotlinMetadata(clazz)) {
- KotlinMetadataUseRegistry registry = type -> addType(type, classContext);
+ KotlinMetadataUseRegistry registry = type -> addType(type, classContext, eventConsumer);
clazz.getKotlinInfo().trace(registry);
clazz.forEachProgramMember(member -> member.getDefinition().getKotlinInfo().trace(registry));
}
@@ -137,46 +145,79 @@
return true;
}
- private void traceSignature(DexProgramClass clazz, DefinitionContext classContext) {
- clazz.getClassSignature().registerUses(type -> addType(type, classContext));
+ private void traceSignature(
+ DexProgramClass clazz,
+ DefinitionContext classContext,
+ UseCollectorEventConsumer eventConsumer) {
+ clazz.getClassSignature().registerUses(type -> addType(type, classContext, eventConsumer));
}
- private void traceSignature(ProgramField field, DefinitionContext fieldContext) {
- field.getDefinition().getGenericSignature().registerUses(type -> addType(type, fieldContext));
+ private void traceSignature(
+ ProgramField field, DefinitionContext fieldContext, UseCollectorEventConsumer eventConsumer) {
+ field
+ .getDefinition()
+ .getGenericSignature()
+ .registerUses(type -> addType(type, fieldContext, eventConsumer));
}
- private void traceSignature(ProgramMethod method, DefinitionContext methodContext) {
- method.getDefinition().getGenericSignature().registerUses(type -> addType(type, methodContext));
+ private void traceSignature(
+ ProgramMethod method,
+ DefinitionContext methodContext,
+ UseCollectorEventConsumer eventConsumer) {
+ method
+ .getDefinition()
+ .getGenericSignature()
+ .registerUses(type -> addType(type, methodContext, eventConsumer));
}
- protected void notifyPresentClass(DexClass clazz, DefinitionContext referencedFrom) {
+ @Override
+ public void notifyPresentClass(DexClass clazz, DefinitionContext referencedFrom) {
TracedClassImpl tracedClass = new TracedClassImpl(clazz, referencedFrom);
consumer.acceptType(tracedClass, diagnostics);
}
- protected void notifyMissingClass(DexType type, DefinitionContext referencedFrom) {
+ @Override
+ public void notifyMissingClass(DexType type, DefinitionContext referencedFrom) {
TracedClassImpl missingClass = new TracedClassImpl(type, referencedFrom);
collectMissingClass(missingClass);
consumer.acceptType(missingClass, diagnostics);
}
- protected void notifyPresentField(DexClassAndField field, DefinitionContext referencedFrom) {
+ @Override
+ public void notifyPresentField(DexClassAndField field, DefinitionContext referencedFrom) {
TracedFieldImpl tracedField = new TracedFieldImpl(field, referencedFrom);
consumer.acceptField(tracedField, diagnostics);
}
- protected void notifyPresentMethod(DexClassAndMethod method, DefinitionContext referencedFrom) {
+ @Override
+ public void notifyMissingField(DexField field, DefinitionContext referencedFrom) {
+ TracedFieldImpl missingField = new TracedFieldImpl(field, referencedFrom);
+ collectMissingField(missingField);
+ consumer.acceptField(missingField, diagnostics);
+ }
+
+ @Override
+ public void notifyPresentMethod(DexClassAndMethod method, DefinitionContext referencedFrom) {
TracedMethodImpl tracedMethod = new TracedMethodImpl(method, referencedFrom);
consumer.acceptMethod(tracedMethod, diagnostics);
}
- protected void notifyPresentMethod(
+ @Override
+ public void notifyPresentMethod(
DexClassAndMethod method, DefinitionContext referencedFrom, DexMethod reference) {
TracedMethodImpl tracedMethod = new TracedMethodImpl(method, referencedFrom, reference);
consumer.acceptMethod(tracedMethod, diagnostics);
}
- protected void notifyPackageOf(Definition definition) {
+ @Override
+ public void notifyMissingMethod(DexMethod method, DefinitionContext referencedFrom) {
+ TracedMethodImpl missingMethod = new TracedMethodImpl(method, referencedFrom);
+ collectMissingMethod(missingMethod);
+ consumer.acceptMethod(missingMethod, diagnostics);
+ }
+
+ @Override
+ public void notifyPackageOf(Definition definition) {
consumer.acceptPackage(
Reference.packageFromString(definition.getContextType().getPackageName()), diagnostics);
}
@@ -197,45 +238,58 @@
return targetPredicate.test(type);
}
- private void addType(DexType type, DefinitionContext referencedFrom) {
+ private void addType(
+ DexType type, DefinitionContext referencedFrom, UseCollectorEventConsumer eventConsumer) {
if (type.isArrayType()) {
- addType(type.toBaseType(factory), referencedFrom);
+ addType(type.toBaseType(factory), referencedFrom, eventConsumer);
return;
}
if (type.isPrimitiveType() || type.isVoidType()) {
return;
}
assert type.isClassType();
- addClassType(type, referencedFrom);
+ addClassType(type, referencedFrom, eventConsumer);
}
- private void addTypes(DexTypeList types, DefinitionContext referencedFrom) {
+ private void addTypes(
+ DexTypeList types,
+ DefinitionContext referencedFrom,
+ UseCollectorEventConsumer eventConsumer) {
for (DexType type : types) {
- addType(type, referencedFrom);
+ addType(type, referencedFrom, eventConsumer);
}
}
private void addClassType(
- DexType type, DefinitionContext referencedFrom, Consumer<DexClass> resolvedClassesConsumer) {
+ DexType type,
+ DefinitionContext referencedFrom,
+ UseCollectorEventConsumer eventConsumer,
+ Consumer<DexClass> resolvedClassesConsumer) {
assert type.isClassType();
ClassResolutionResult result =
appView.contextIndependentDefinitionForWithResolutionResult(type);
if (result.hasClassResolutionResult()) {
result.forEachClassResolutionResult(resolvedClassesConsumer);
} else {
- notifyMissingClass(type, referencedFrom);
+ eventConsumer.notifyMissingClass(type, referencedFrom);
}
}
- private void addClassType(DexType type, DefinitionContext referencedFrom) {
- addClassType(type, referencedFrom, clazz -> addClass(clazz, referencedFrom));
+ private void addClassType(
+ DexType type, DefinitionContext referencedFrom, UseCollectorEventConsumer eventConsumer) {
+ addClassType(
+ type,
+ referencedFrom,
+ eventConsumer,
+ clazz -> addClass(clazz, referencedFrom, eventConsumer));
}
- private void addClass(DexClass clazz, DefinitionContext referencedFrom) {
+ private void addClass(
+ DexClass clazz, DefinitionContext referencedFrom, UseCollectorEventConsumer eventConsumer) {
if (isTargetType(clazz.getType())) {
- notifyPresentClass(clazz, referencedFrom);
+ eventConsumer.notifyPresentClass(clazz, referencedFrom);
if (clazz.getAccessFlags().isPackagePrivateOrProtected()) {
- notifyPackageOf(clazz);
+ eventConsumer.notifyPackageOf(clazz);
}
}
}
@@ -285,39 +339,51 @@
collectMissing(tracedMethod, missingMethods);
}
- private void registerField(ProgramField field) {
+ private void registerField(ProgramField field, UseCollectorEventConsumer eventConsumer) {
DefinitionContext referencedFrom = DefinitionContextUtils.create(field);
- addType(field.getType(), referencedFrom);
+ addType(field.getType(), referencedFrom, eventConsumer);
field
.getAnnotations()
.forEach(
- dexAnnotation -> registerAnnotation(dexAnnotation, field.getHolder(), referencedFrom));
- traceSignature(field, referencedFrom);
+ dexAnnotation ->
+ registerAnnotation(
+ dexAnnotation, field.getHolder(), referencedFrom, eventConsumer));
+ traceSignature(field, referencedFrom, eventConsumer);
}
- private void registerMethod(ProgramMethod method) {
+ private void registerMethod(ProgramMethod method, UseCollectorEventConsumer eventConsumer) {
DefinitionContext referencedFrom = DefinitionContextUtils.create(method);
- addTypes(method.getParameters(), referencedFrom);
- addType(method.getReturnType(), referencedFrom);
+ addTypes(method.getParameters(), referencedFrom, eventConsumer);
+ addType(method.getReturnType(), referencedFrom, eventConsumer);
method
.getAnnotations()
.forEach(
- dexAnnotation -> registerAnnotation(dexAnnotation, method.getHolder(), referencedFrom));
+ dexAnnotation ->
+ registerAnnotation(
+ dexAnnotation, method.getHolder(), referencedFrom, eventConsumer));
method
.getParameterAnnotations()
.forEachAnnotation(
- dexAnnotation -> registerAnnotation(dexAnnotation, method.getHolder(), referencedFrom));
- traceCode(method);
- traceSignature(method, referencedFrom);
+ dexAnnotation ->
+ registerAnnotation(
+ dexAnnotation, method.getHolder(), referencedFrom, eventConsumer));
+ traceCode(method, referencedFrom, eventConsumer);
+ traceSignature(method, referencedFrom, eventConsumer);
}
- private void traceCode(ProgramMethod method) {
- method.registerCodeReferences(new MethodUseCollector(method));
+ private void traceCode(
+ ProgramMethod method,
+ DefinitionContext referencedFrom,
+ UseCollectorEventConsumer eventConsumer) {
+ method.registerCodeReferences(new MethodUseCollector(method, referencedFrom, eventConsumer));
}
private void registerSuperType(
- DexProgramClass clazz, DexType superType, DefinitionContext referencedFrom) {
- addType(superType, referencedFrom);
+ DexProgramClass clazz,
+ DexType superType,
+ DefinitionContext referencedFrom,
+ UseCollectorEventConsumer eventConsumer) {
+ addType(superType, referencedFrom, eventConsumer);
// If clazz overrides any methods in superType, we should keep those as well.
clazz.forEachProgramVirtualMethod(
method -> {
@@ -345,7 +411,7 @@
resolvedMethod.getReference().withHolder(superType, factory));
} else {
notifyPresentMethod(resolvedMethod, referencedFrom);
- addClass(resolvedMethod.getHolder(), referencedFrom);
+ addClass(resolvedMethod.getHolder(), referencedFrom, eventConsumer);
}
ensurePackageAccessToMember(resolvedMethod, method.getHolder());
}
@@ -353,7 +419,10 @@
}
private void registerAnnotation(
- DexAnnotation annotation, DexProgramClass context, DefinitionContext referencedFrom) {
+ DexAnnotation annotation,
+ DexProgramClass context,
+ DefinitionContext referencedFrom,
+ UseCollectorEventConsumer eventConsumer) {
DexType type = annotation.getAnnotationType();
assert type.isClassType();
if (type.isIdenticalTo(factory.annotationMethodParameters)
@@ -383,7 +452,10 @@
element -> {
assert element.getValue().isDexValueAnnotation();
registerEncodedAnnotation(
- element.getValue().asDexValueAnnotation().getValue(), context, referencedFrom);
+ element.getValue().asDexValueAnnotation().getValue(),
+ context,
+ referencedFrom,
+ eventConsumer);
});
return;
}
@@ -395,7 +467,10 @@
if (type.isIdenticalTo(factory.annotationThrows)) {
assert referencedFrom.isMethodContext();
registerDexValue(
- annotation.annotation.elements[0].value.asDexValueArray(), context, referencedFrom);
+ annotation.annotation.elements[0].value.asDexValueArray(),
+ context,
+ referencedFrom,
+ eventConsumer);
return;
}
assert !type.getDescriptor().startsWith(factory.dalvikAnnotationPrefix)
@@ -403,16 +478,20 @@
+ factory.dalvikAnnotationPrefix
+ ": "
+ type.getDescriptor();
- registerEncodedAnnotation(annotation.getAnnotation(), context, referencedFrom);
+ registerEncodedAnnotation(annotation.getAnnotation(), context, referencedFrom, eventConsumer);
}
void registerEncodedAnnotation(
- DexEncodedAnnotation annotation, DexProgramClass context, DefinitionContext referencedFrom) {
+ DexEncodedAnnotation annotation,
+ DexProgramClass context,
+ DefinitionContext referencedFrom,
+ UseCollectorEventConsumer eventConsumer) {
addClassType(
annotation.getType(),
referencedFrom,
+ eventConsumer,
resolvedClass -> {
- addClass(resolvedClass, referencedFrom);
+ addClass(resolvedClass, referencedFrom, eventConsumer);
// For annotations in target handle annotation "methods" used to set values.
annotation.forEachElement(
element -> {
@@ -422,29 +501,35 @@
method -> notifyPresentMethod(method, referencedFrom));
}
// Handle the argument values passed to the annotation "method".
- registerDexValue(element.getValue(), context, referencedFrom);
+ registerDexValue(element.getValue(), context, referencedFrom, eventConsumer);
});
});
}
private void registerDexValue(
- DexValue value, DexProgramClass context, DefinitionContext referencedFrom) {
+ DexValue value,
+ DexProgramClass context,
+ DefinitionContext referencedFrom,
+ UseCollectorEventConsumer eventConsumer) {
if (value.isDexValueType()) {
- addType(value.asDexValueType().getValue(), referencedFrom);
+ addType(value.asDexValueType().getValue(), referencedFrom, eventConsumer);
} else if (value.isDexValueEnum()) {
DexField field = value.asDexValueEnum().value;
- handleRewrittenFieldReference(field, context, referencedFrom);
+ handleRewrittenFieldReference(field, context, referencedFrom, eventConsumer);
} else if (value.isDexValueArray()) {
for (DexValue elementValue : value.asDexValueArray().getValues()) {
- registerDexValue(elementValue, context, referencedFrom);
+ registerDexValue(elementValue, context, referencedFrom, eventConsumer);
}
}
}
private void handleRewrittenFieldReference(
- DexField field, DexProgramClass context, DefinitionContext referencedFrom) {
- addType(field.getHolderType(), referencedFrom);
- addType(field.getType(), referencedFrom);
+ DexField field,
+ DexProgramClass context,
+ DefinitionContext referencedFrom,
+ UseCollectorEventConsumer eventConsumer) {
+ addType(field.getHolderType(), referencedFrom, eventConsumer);
+ addType(field.getType(), referencedFrom, eventConsumer);
FieldResolutionResult resolutionResult = appInfo().resolveField(field);
if (resolutionResult.hasSuccessfulResolutionResult()) {
resolutionResult.forEachSuccessfulFieldResolutionResult(
@@ -456,19 +541,22 @@
}
});
} else {
- TracedFieldImpl missingField = new TracedFieldImpl(field, referencedFrom);
- collectMissingField(missingField);
- consumer.acceptField(missingField, diagnostics);
+ notifyMissingField(field, referencedFrom);
}
}
class MethodUseCollector extends UseRegistry<ProgramMethod> {
private final DefinitionContext referencedFrom;
+ private final UseCollectorEventConsumer eventConsumer;
- public MethodUseCollector(ProgramMethod context) {
+ public MethodUseCollector(
+ ProgramMethod context,
+ DefinitionContext referencedFrom,
+ UseCollectorEventConsumer eventConsumer) {
super(appView(), context);
- this.referencedFrom = DefinitionContextUtils.create(context);
+ this.referencedFrom = referencedFrom;
+ this.eventConsumer = eventConsumer;
}
// Method references.
@@ -541,7 +629,7 @@
DexMethod method = lookupResult.getReference();
if (method.getHolderType().isArrayType()) {
assert lookupResult.getType().isVirtual();
- addType(method.getHolderType(), referencedFrom);
+ addType(method.getHolderType(), referencedFrom, eventConsumer);
return;
}
assert lookupResult.getType().isInterface() || lookupResult.getType().isVirtual();
@@ -564,7 +652,7 @@
result
.asFailedResolution()
.forEachFailureDependency(
- type -> addType(type, referencedFrom),
+ type -> addType(type, referencedFrom, eventConsumer),
methodCausingFailure ->
handleRewrittenMethodReference(
method, methodCausingFailure.asDexClassAndMethod(appView)));
@@ -586,9 +674,9 @@
private void handleRewrittenMethodReference(
DexMethod method, DexClassAndMethod resolvedMethod) {
- addType(method.getHolderType(), referencedFrom);
- addTypes(method.getParameters(), referencedFrom);
- addType(method.getReturnType(), referencedFrom);
+ addType(method.getHolderType(), referencedFrom, eventConsumer);
+ addTypes(method.getParameters(), referencedFrom, eventConsumer);
+ addType(method.getReturnType(), referencedFrom, eventConsumer);
if (resolvedMethod != null) {
DexEncodedMethod definition = resolvedMethod.getDefinition();
assert resolvedMethod.getReference().match(method)
@@ -598,9 +686,7 @@
notifyPresentMethod(resolvedMethod, referencedFrom);
}
} else {
- TracedMethodImpl missingMethod = new TracedMethodImpl(method, referencedFrom);
- collectMissingMethod(missingMethod);
- consumer.acceptMethod(missingMethod, diagnostics);
+ notifyMissingMethod(method, referencedFrom);
}
}
@@ -610,7 +696,8 @@
public void registerInitClass(DexType clazz) {
DexType rewrittenClass = graphLens().lookupType(clazz);
DexField clinitField = appView.initClassLens().getInitClassField(rewrittenClass);
- handleRewrittenFieldReference(clinitField, getContext().getHolder(), referencedFrom);
+ handleRewrittenFieldReference(
+ clinitField, getContext().getHolder(), referencedFrom, eventConsumer);
}
@Override
@@ -636,14 +723,14 @@
private void handleFieldAccess(DexField field) {
FieldLookupResult lookupResult = graphLens().lookupFieldResult(field);
handleRewrittenFieldReference(
- lookupResult.getReference(), getContext().getHolder(), referencedFrom);
+ lookupResult.getReference(), getContext().getHolder(), referencedFrom, eventConsumer);
}
// Type references.
@Override
public void registerTypeReference(DexType type) {
- addType(graphLens().lookupType(type), referencedFrom);
+ addType(graphLens().lookupType(type), referencedFrom, eventConsumer);
}
// Call sites.
diff --git a/src/main/java/com/android/tools/r8/tracereferences/UseCollectorEventConsumer.java b/src/main/java/com/android/tools/r8/tracereferences/UseCollectorEventConsumer.java
new file mode 100644
index 0000000..a1467da
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/tracereferences/UseCollectorEventConsumer.java
@@ -0,0 +1,33 @@
+// Copyright (c) 2025, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.tracereferences;
+
+import com.android.tools.r8.diagnostic.DefinitionContext;
+import com.android.tools.r8.graph.Definition;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndField;
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+
+public interface UseCollectorEventConsumer {
+
+ void notifyPresentClass(DexClass clazz, DefinitionContext referencedFrom);
+
+ void notifyMissingClass(DexType type, DefinitionContext referencedFrom);
+
+ void notifyPresentField(DexClassAndField field, DefinitionContext referencedFrom);
+
+ void notifyMissingField(DexField field, DefinitionContext referencedFrom);
+
+ void notifyPresentMethod(DexClassAndMethod method, DefinitionContext referencedFrom);
+
+ void notifyPresentMethod(
+ DexClassAndMethod method, DefinitionContext referencedFrom, DexMethod reference);
+
+ void notifyMissingMethod(DexMethod method, DefinitionContext referencedFrom);
+
+ void notifyPackageOf(Definition definition);
+}