Delete kotlin lambda merger
Fixes: 172800423
Fixes: 174809311
Bug: 179019716
Bug: 179018501
Bug: 173337498
Bug: 141719453
Change-Id: Ia0ef62d9e52a5dcbe2cd1064386a76951fd3c0db
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index da20df4..c5eac58 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -476,7 +476,6 @@
assert !internal.enableEnumValueOptimization;
assert !internal.outline.enabled;
assert !internal.enableValuePropagation;
- assert !internal.enableLambdaMerging;
assert !internal.enableTreeShakingOfLibraryMethodOverrides;
internal.desugarState = getDesugarState();
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 8bf7cc6..b552bb2 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -174,7 +174,6 @@
assert !internal.enableEnumValueOptimization;
assert !internal.outline.enabled;
assert !internal.enableValuePropagation;
- assert !internal.enableLambdaMerging;
assert !internal.enableTreeShakingOfLibraryMethodOverrides;
assert internal.desugarState == DesugarState.ON;
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 0fa55a7..8d07b18 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -834,10 +834,6 @@
internal.desugarState = getDesugarState();
assert internal.isShrinking() == getEnableTreeShaking();
assert internal.isMinifying() == getEnableMinification();
- // In current implementation we only enable lambda merger if the tree
- // shaking is enabled. This is caused by the fact that we rely on tree
- // shaking for removing the lambda classes which should be revised later.
- internal.enableLambdaMerging = getEnableTreeShaking();
assert !internal.ignoreMissingClasses;
internal.ignoreMissingClasses =
proguardConfiguration.isIgnoreWarnings()
@@ -871,14 +867,12 @@
internal.enableClassStaticizer = false;
internal.outline.enabled = false;
internal.enableEnumUnboxing = false;
- internal.enableLambdaMerging = false;
}
if (!internal.isShrinking()) {
// If R8 is not shrinking, there is no point in running various optimizations since the
// optimized classes will still remain in the program (the application size could increase).
internal.enableEnumUnboxing = false;
internal.horizontalClassMergerOptions().disable();
- internal.enableLambdaMerging = false;
internal.enableVerticalClassMerging = false;
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 7d574dd..3b0475f 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.DexValue.DexValueString;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis.InitializedClassesInInstanceMethods;
-import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
import com.android.tools.r8.graph.classmerging.MergedClassesCollection;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.horizontalclassmerging.HorizontallyMergedClasses;
@@ -91,7 +90,6 @@
private boolean allCodeProcessed = false;
private Predicate<DexType> classesEscapingIntoLibrary = Predicates.alwaysTrue();
private InitializedClassesInInstanceMethods initializedClassesInInstanceMethods;
- private HorizontallyMergedLambdaClasses horizontallyMergedLambdaClasses;
private HorizontallyMergedClasses horizontallyMergedClasses;
private VerticallyMergedClasses verticallyMergedClasses;
private EnumDataMap unboxedEnums = EnumDataMap.empty();
@@ -483,9 +481,6 @@
if (horizontallyMergedClasses != null) {
collection.add(horizontallyMergedClasses);
}
- if (horizontallyMergedLambdaClasses != null) {
- collection.add(horizontallyMergedLambdaClasses);
- }
if (verticallyMergedClasses != null) {
collection.add(verticallyMergedClasses);
}
@@ -493,23 +488,6 @@
}
/**
- * Get the result of horizontal lambda class merging. Returns null if horizontal lambda class
- * merging has not been run.
- */
- public HorizontallyMergedLambdaClasses horizontallyMergedLambdaClasses() {
- return horizontallyMergedLambdaClasses;
- }
-
- public void setHorizontallyMergedLambdaClasses(
- HorizontallyMergedLambdaClasses horizontallyMergedLambdaClasses) {
- assert this.horizontallyMergedLambdaClasses == null;
- this.horizontallyMergedLambdaClasses = horizontallyMergedLambdaClasses;
- testing()
- .horizontallyMergedLambdaClassesConsumer
- .accept(dexItemFactory(), horizontallyMergedLambdaClasses);
- }
-
- /**
* Get the result of horizontal class merging. Returns null if horizontal class merging has not
* been run.
*/
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java b/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java
deleted file mode 100644
index 3a9f618..0000000
--- a/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2019, 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.graph.classmerging;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroup;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
-import com.android.tools.r8.utils.collections.BidirectionalManyToOneMap;
-import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneMap;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.BiConsumer;
-
-public class HorizontallyMergedLambdaClasses implements MergedClasses {
-
- private final BidirectionalManyToOneMap<DexType, DexType> mergedClasses;
-
- public HorizontallyMergedLambdaClasses(Map<DexType, LambdaGroup> lambdas) {
- MutableBidirectionalManyToOneMap<DexType, DexType> mergedClasses =
- new BidirectionalManyToOneHashMap<>();
- lambdas.forEach((lambda, group) -> mergedClasses.put(lambda, group.getGroupClassType()));
- this.mergedClasses = mergedClasses;
- }
-
- public static HorizontallyMergedLambdaClasses empty() {
- return new HorizontallyMergedLambdaClasses(Collections.emptyMap());
- }
-
- @Override
- public void forEachMergeGroup(BiConsumer<Set<DexType>, DexType> consumer) {
- mergedClasses.forEachManyToOneMapping(consumer);
- }
-
- @Override
- public boolean hasBeenMergedIntoDifferentType(DexType type) {
- return mergedClasses.containsKey(type);
- }
-
- @Override
- public boolean isMergeTarget(DexType type) {
- return mergedClasses.containsValue(type);
- }
-
- @Override
- public boolean verifyAllSourcesPruned(AppView<AppInfoWithLiveness> appView) {
- for (DexType source : mergedClasses.keySet()) {
- assert appView.appInfo().wasPruned(source)
- : "Expected horizontally merged lambda class `"
- + source.toSourceString()
- + "` to be absent";
- }
- return true;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index dd0486a..ef1b786 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -23,7 +23,6 @@
import com.android.tools.r8.horizontalclassmerging.policies.NoInnerClasses;
import com.android.tools.r8.horizontalclassmerging.policies.NoInterfaces;
import com.android.tools.r8.horizontalclassmerging.policies.NoKeepRules;
-import com.android.tools.r8.horizontalclassmerging.policies.NoKotlinLambdas;
import com.android.tools.r8.horizontalclassmerging.policies.NoKotlinMetadata;
import com.android.tools.r8.horizontalclassmerging.policies.NoNativeMethods;
import com.android.tools.r8.horizontalclassmerging.policies.NoServiceLoaders;
@@ -138,13 +137,12 @@
new NoEnums(appView),
new CheckAbstractClasses(appView),
new IgnoreSynthetics(appView),
- new NoClassesOrMembersWithAnnotations(),
+ new NoClassesOrMembersWithAnnotations(appView),
new NoInnerClasses(),
new NoClassInitializerWithObservableSideEffects(),
new NoNativeMethods(),
new NoKeepRules(appView),
new NoKotlinMetadata(),
- new NoKotlinLambdas(appView),
new NoServiceLoaders(appView),
new NotVerticallyMergedIntoSubtype(appView),
new NoDirectRuntimeTypeChecks(runtimeTypeCheckInfo),
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassesOrMembersWithAnnotations.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassesOrMembersWithAnnotations.java
index f9d2106..f0b2a6e 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassesOrMembersWithAnnotations.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassesOrMembersWithAnnotations.java
@@ -4,12 +4,28 @@
package com.android.tools.r8.horizontalclassmerging.policies;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.InternalOptions.HorizontalClassMergerOptions;
public class NoClassesOrMembersWithAnnotations extends SingleClassPolicy {
+
+ private final HorizontalClassMergerOptions options;
+
+ public NoClassesOrMembersWithAnnotations(AppView<AppInfoWithLiveness> appView) {
+ this.options = appView.options().horizontalClassMergerOptions();
+ }
+
@Override
public boolean canMerge(DexProgramClass program) {
return !program.hasClassOrMemberAnnotations();
}
+
+ @Override
+ public boolean shouldSkipPolicy() {
+ // TODO(b/179019716): Add support for merging in presence of annotations.
+ return options.skipNoClassesOrMembersWithAnnotationsPolicyForTesting;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInnerClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInnerClasses.java
index ddb2aef..cc9f61c 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInnerClasses.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInnerClasses.java
@@ -11,6 +11,7 @@
@Override
public boolean canMerge(DexProgramClass program) {
+ // TODO(b/179018501): allow merging classes with inner/outer classes.
return program.getInnerClasses().isEmpty();
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinLambdas.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinLambdas.java
deleted file mode 100644
index dee7a4a..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinLambdas.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2020, 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.horizontalclassmerging.policies;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-
-public class NoKotlinLambdas extends SingleClassPolicy {
- private final AppView<AppInfoWithLiveness> appView;
-
- public NoKotlinLambdas(AppView<AppInfoWithLiveness> appView) {
- this.appView = appView;
- }
-
- @Override
- public boolean shouldSkipPolicy() {
- return appView.options().horizontalClassMergerOptions().isKotlinLambdaMergingEnabled();
- }
-
- @Override
- public boolean canMerge(DexProgramClass program) {
- if (program.getKotlinInfo().isNoKotlinInformation()
- || !program.getKotlinInfo().isSyntheticClass()) {
- return true;
- }
-
- return !program.getKotlinInfo().asSyntheticClass().isLambda();
- }
-}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinMetadata.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinMetadata.java
index 92f2938..1acad7a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinMetadata.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinMetadata.java
@@ -19,12 +19,8 @@
}
private boolean verifyNoUnexpectedKotlinInfo(DexProgramClass clazz) {
- if (clazz.getKotlinInfo().isNoKotlinInformation()) {
- assert verifyNoUnexpectedKotlinMemberInfo(clazz);
- return true;
- }
- assert clazz.getKotlinInfo().isSyntheticClass()
- && clazz.getKotlinInfo().asSyntheticClass().isLambda();
+ assert clazz.getKotlinInfo().isNoKotlinInformation();
+ assert verifyNoUnexpectedKotlinMemberInfo(clazz);
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 6960b96..22ee5c5 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -23,7 +23,6 @@
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
import com.android.tools.r8.ir.analysis.TypeChecker;
import com.android.tools.r8.ir.analysis.VerifyTypesHelper;
import com.android.tools.r8.ir.analysis.constant.SparseConditionalConstantPropagation;
@@ -82,7 +81,6 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
-import com.android.tools.r8.ir.optimize.lambda.LambdaMerger;
import com.android.tools.r8.ir.optimize.staticizer.ClassStaticizer;
import com.android.tools.r8.ir.optimize.string.StringBuilderOptimizer;
import com.android.tools.r8.ir.optimize.string.StringOptimizer;
@@ -140,7 +138,6 @@
private final TwrCloseResourceRewriter twrCloseResourceRewriter;
private final BackportedMethodRewriter backportedMethodRewriter;
private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
- private final LambdaMerger lambdaMerger;
private final ClassInliner classInliner;
private final ClassStaticizer classStaticizer;
private final InternalOptions options;
@@ -242,7 +239,6 @@
: null;
this.d8NestBasedAccessDesugaring =
options.shouldDesugarNests() ? new D8NestBasedAccessDesugaring(appView) : null;
- this.lambdaMerger = null;
this.covariantReturnTypeAnnotationTransformer = null;
this.dynamicTypeOptimization = null;
this.classInliner = null;
@@ -305,12 +301,9 @@
options.enableTreeShakingOfLibraryMethodOverrides
? new LibraryMethodOverrideAnalysis(appViewWithLiveness)
: null;
- this.lambdaMerger =
- options.enableLambdaMerging ? new LambdaMerger(appViewWithLiveness) : null;
this.enumUnboxer = options.enableEnumUnboxing ? new EnumUnboxer(appViewWithLiveness) : null;
this.lensCodeRewriter = new LensCodeRewriter(appViewWithLiveness, enumUnboxer);
- this.inliner =
- new Inliner(appViewWithLiveness, mainDexClasses, lambdaMerger, lensCodeRewriter);
+ this.inliner = new Inliner(appViewWithLiveness, mainDexClasses, lensCodeRewriter);
this.outliner = new Outliner(appViewWithLiveness);
this.memberValuePropagation =
options.enableValuePropagation ? new MemberValuePropagation(appViewWithLiveness) : null;
@@ -346,7 +339,6 @@
this.fieldAccessAnalysis = null;
this.libraryMethodOverrideAnalysis = null;
this.inliner = null;
- this.lambdaMerger = null;
this.outliner = null;
this.memberValuePropagation = null;
this.lensCodeRewriter = null;
@@ -674,7 +666,6 @@
DexApplication application = appView.appInfo().app();
computeReachabilitySensitivity(application);
- collectLambdaMergingCandidates(application);
collectStaticizerCandidates(application);
workaroundAbstractMethodOnNonAbstractClassVerificationBug(
executorService, simpleOptimizationFeedback);
@@ -800,10 +791,6 @@
synthesizeRetargetClass(builder, executorService);
synthesizeEnumUnboxingUtilityMethods(executorService);
- printPhase("Lambda merging finalization");
- // TODO(b/127694949): Adapt to PostOptimization.
- finalizeLambdaMerging(application, feedback, builder, executorService, initialGraphLensForIR);
-
printPhase("Desugared library API Conversion finalization");
generateDesugaredLibraryAPIWrappers(builder, executorService);
@@ -962,28 +949,6 @@
method, code, OptimizationFeedbackIgnore.getInstance(), Timing.empty());
}
- private void collectLambdaMergingCandidates(DexApplication application) {
- if (lambdaMerger != null) {
- lambdaMerger.collectGroupCandidates(application);
- }
- }
-
- private void finalizeLambdaMerging(
- DexApplication application,
- OptimizationFeedback feedback,
- Builder<?> builder,
- ExecutorService executorService,
- GraphLens appliedGraphLens)
- throws ExecutionException {
- if (lambdaMerger != null) {
- lambdaMerger.applyLambdaClassMapping(
- application, this, feedback, builder, executorService, appliedGraphLens);
- } else {
- appView.setHorizontallyMergedLambdaClasses(HorizontallyMergedLambdaClasses.empty());
- }
- assert appView.horizontallyMergedLambdaClasses() != null;
- }
-
private void generateDesugaredLibraryAPIWrappers(
DexApplication.Builder<?> builder, ExecutorService executorService)
throws ExecutionException {
@@ -1233,13 +1198,6 @@
|| !appView.appInfo().withLiveness().isNeverReprocessMethod(method.method)
: "Illegal reprocessing due to -neverreprocess rule: " + context.toSourceString();
- if (lambdaMerger != null) {
- timing.begin("Merge lambdas");
- lambdaMerger.rewriteCode(code.context(), code, inliner, methodProcessor);
- timing.end();
- assert code.isConsistentSSA();
- }
-
if (typeChecker != null && !typeChecker.check(code)) {
assert appView.enableWholeProgramOptimizations();
assert options.testing.allowTypeErrors;
@@ -1542,15 +1500,6 @@
previous = printMethod(code, "IR after twr close resource rewriter (SSA)", previous);
- if (lambdaMerger != null) {
- timing.begin("Analyze lambda merging");
- lambdaMerger.analyzeCode(code.context(), code);
- timing.end();
- assert code.isConsistentSSA();
- }
-
- previous = printMethod(code, "IR after lambda merger (SSA)", previous);
-
// TODO(b/140766440): an ideal solution would be puttting CodeOptimization for this into
// the list for primary processing only.
if (options.outline.enabled && outliner != null && methodProcessor.isPrimaryMethodProcessor()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 7eca624..9e726b9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -57,7 +57,6 @@
import com.android.tools.r8.ir.optimize.inliner.InliningReasonStrategy;
import com.android.tools.r8.ir.optimize.inliner.NopWhyAreYouNotInliningReporter;
import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
-import com.android.tools.r8.ir.optimize.lambda.LambdaMerger;
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.MainDexTracingResult;
@@ -84,7 +83,6 @@
protected final AppView<AppInfoWithLiveness> appView;
private final Set<DexMethod> extraNeverInlineMethods;
- private final LambdaMerger lambdaMerger;
private final LensCodeRewriter lensCodeRewriter;
final MainDexTracingResult mainDexClasses;
@@ -100,7 +98,6 @@
public Inliner(
AppView<AppInfoWithLiveness> appView,
MainDexTracingResult mainDexClasses,
- LambdaMerger lambdaMerger,
LensCodeRewriter lensCodeRewriter) {
Kotlin.Intrinsics intrinsics = appView.dexItemFactory().kotlin.intrinsics;
this.appView = appView;
@@ -108,7 +105,6 @@
appView.options().kotlinOptimizationOptions().disableKotlinSpecificOptimizations
? ImmutableSet.of()
: ImmutableSet.of(intrinsics.throwNpe, intrinsics.throwParameterIsNullException);
- this.lambdaMerger = lambdaMerger;
this.lensCodeRewriter = lensCodeRewriter;
this.mainDexClasses = mainDexClasses;
availableApiExceptions =
@@ -596,7 +592,6 @@
InvokeMethod invoke,
ProgramMethod context,
InliningIRProvider inliningIRProvider,
- LambdaMerger lambdaMerger,
LensCodeRewriter lensCodeRewriter) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
InternalOptions options = appView.options();
@@ -743,9 +738,6 @@
assert lensCodeRewriter != null;
lensCodeRewriter.rewrite(code, target);
}
- if (lambdaMerger != null) {
- lambdaMerger.rewriteCodeForInlining(target, code, context, inliningIRProvider);
- }
if (options.testing.inlineeIrModifier != null) {
options.testing.inlineeIrModifier.accept(code);
}
@@ -1040,7 +1032,7 @@
InlineeWithReason inlinee =
action.buildInliningIR(
- appView, invoke, context, inliningIRProvider, lambdaMerger, lensCodeRewriter);
+ appView, invoke, context, inliningIRProvider, lensCodeRewriter);
if (strategy.willExceedBudget(
code, invoke, inlinee, block, whyAreYouNotInliningReporter)) {
assert whyAreYouNotInliningReporter.unsetReasonHasBeenReportedFlag();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/CaptureSignature.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/CaptureSignature.java
deleted file mode 100644
index 5a39e71..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/CaptureSignature.java
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda;
-
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
-import it.unimi.dsi.fastutil.ints.IntArrayList;
-import it.unimi.dsi.fastutil.ints.IntList;
-import it.unimi.dsi.fastutil.ints.IntLists;
-import java.util.Arrays;
-import java.util.BitSet;
-import java.util.Comparator;
-import java.util.List;
-import java.util.function.IntFunction;
-
-// While mapping fields representing lambda captures we rearrange fields to make sure
-// lambdas having different order of the fields still can be merged. We also store
-// all captures of reference types in fields of java.lang.Objects class.
-//
-// This allows us to use same lambda groups class for these two different lambdas:
-//
-// Lambda Group Class Lambda$1 Lambda$2
-// Object $c0 int foo -> $c1 char foo -> $c2
-// int $c1 String[] bar -> $c0 int bar -> $c1
-// char $c2 char baz -> $c2 List baz -> $c0
-//
-// Capture signature is represented by a string with sorted shorties of field
-// types, such as "CIL" for both Lambda$1 and Lambda$2 in the above example.
-//
-public final class CaptureSignature {
- private static final IntList EMPTY_LIST = IntLists.EMPTY_LIST;
- private static final IntList SINGLE_LIST = IntLists.singleton(0);
-
- private CaptureSignature() {
- }
-
- // Returns an array representing mapping of fields of the normalized capture
- // into fields of original capture such that:
- //
- // mapping = getReverseCaptureMapping(...)
- // <original-capture-index> = mapping[<normalized-capture-index>]
- public static IntList getReverseCaptureMapping(DexType[] types) {
- if (types.length == 0) {
- return EMPTY_LIST;
- }
-
- if (types.length == 1) {
- return SINGLE_LIST;
- }
-
- IntList result = new IntArrayList(types.length);
- for (int i = 0; i < types.length; i++) {
- result.add(i);
- }
- // Sort the indices by shorties (sorting is stable).
- result.sort(Comparator.comparingInt(i -> types[i].toShorty()));
- assert verifyMapping(result);
- return result;
- }
-
- // Given a capture signature and an index returns the type of the field.
- public static DexType fieldType(DexItemFactory factory, String capture, int index) {
- switch (capture.charAt(index)) {
- case 'L':
- return factory.objectType;
- case 'Z':
- return factory.booleanType;
- case 'B':
- return factory.byteType;
- case 'S':
- return factory.shortType;
- case 'C':
- return factory.charType;
- case 'I':
- return factory.intType;
- case 'F':
- return factory.floatType;
- case 'J':
- return factory.longType;
- case 'D':
- return factory.doubleType;
- default:
- throw new Unreachable("Invalid capture character: " + capture.charAt(index));
- }
- }
-
- private static String getCaptureSignature(int size, IntFunction<DexType> type) {
- if (size == 0) {
- return "";
- }
- if (size == 1) {
- return Character.toString(type.apply(0).toShorty());
- }
-
- char[] chars = new char[size];
- for (int i = 0; i < size; i++) {
- chars[i] = type.apply(i).toShorty();
- }
- Arrays.sort(chars);
- return new String(chars);
- }
-
- // Compute capture signature based on lambda class capture fields.
- public static String getCaptureSignature(List<DexEncodedField> fields) {
- return getCaptureSignature(fields.size(), i -> fields.get(i).field.type);
- }
-
- // Compute capture signature based on type list.
- public static String getCaptureSignature(DexTypeList types) {
- return getCaptureSignature(types.values.length, i -> types.values[i]);
- }
-
- // Having a list of fields of lambda captured values, maps one of them into
- // an index of the appropriate field in normalized capture signature.
- public static int mapFieldIntoCaptureIndex(
- String capture, List<DexEncodedField> lambdaFields, DexField fieldToMap) {
- char fieldKind = fieldToMap.type.toShorty();
- int numberOfSameCaptureKind = 0;
- int result = -1;
-
- for (DexEncodedField encodedField : lambdaFields) {
- if (encodedField.field == fieldToMap) {
- result = numberOfSameCaptureKind;
- break;
- }
- if (encodedField.field.type.toShorty() == fieldKind) {
- numberOfSameCaptureKind++;
- }
- }
-
- assert result >= 0 : "Field was not found in the lambda class.";
-
- for (int index = 0; index < capture.length(); index++) {
- if (capture.charAt(index) == fieldKind) {
- if (result == 0) {
- return index;
- }
- result--;
- }
- }
-
- throw new Unreachable("Were not able to map lambda field into capture index");
- }
-
- private static boolean verifyMapping(IntList mapping) {
- BitSet bits = new BitSet();
- for (Integer i : mapping) {
- assert i >= 0 && i < mapping.size();
- assert !bits.get(i);
- bits.set(i);
- }
- return true;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java
deleted file mode 100644
index 1da512d..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java
+++ /dev/null
@@ -1,430 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda;
-
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.code.Argument;
-import com.android.tools.r8.ir.code.BasicBlock;
-import com.android.tools.r8.ir.code.CheckCast;
-import com.android.tools.r8.ir.code.ConstClass;
-import com.android.tools.r8.ir.code.ConstMethodHandle;
-import com.android.tools.r8.ir.code.ConstMethodType;
-import com.android.tools.r8.ir.code.DefaultInstructionVisitor;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.InitClass;
-import com.android.tools.r8.ir.code.InstanceGet;
-import com.android.tools.r8.ir.code.InstancePut;
-import com.android.tools.r8.ir.code.InstructionListIterator;
-import com.android.tools.r8.ir.code.Invoke;
-import com.android.tools.r8.ir.code.InvokeMethod;
-import com.android.tools.r8.ir.code.NewArrayEmpty;
-import com.android.tools.r8.ir.code.NewInstance;
-import com.android.tools.r8.ir.code.StaticGet;
-import com.android.tools.r8.ir.code.StaticPut;
-import com.android.tools.r8.ir.optimize.lambda.LambdaMerger.ApplyStrategy;
-import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import java.util.ListIterator;
-import java.util.function.Function;
-
-// Performs processing of the method code (all methods) needed by lambda rewriter.
-//
-// Functionality can be modified by strategy (specific to lambda group) and lambda
-// type visitor.
-//
-// In general it is used to
-// (a) track the code for illegal lambda type usages inside the code, and
-// (b) patching valid lambda type references to point to lambda group classes instead.
-//
-// This class is also used inside particular strategies as a context of the instruction
-// being checked or patched, it provides access to code, block and instruction iterators.
-public abstract class CodeProcessor extends DefaultInstructionVisitor<Void> {
- // Strategy (specific to lambda group) for detecting valid references to the
- // lambda classes (of this group) and patching them with group class references.
- public interface Strategy {
- LambdaGroup group();
-
- boolean isValidStaticFieldWrite(CodeProcessor context, DexField field);
-
- boolean isValidStaticFieldRead(CodeProcessor context, DexField field);
-
- boolean isValidInstanceFieldWrite(CodeProcessor context, DexField field);
-
- boolean isValidInstanceFieldRead(CodeProcessor context, DexField field);
-
- boolean isValidInvoke(CodeProcessor context, InvokeMethod invoke);
-
- boolean isValidNewInstance(CodeProcessor context, NewInstance invoke);
-
- boolean isValidInitClass(CodeProcessor context, DexType clazz);
-
- boolean isValidHolder(CodeProcessor context, DexType holder);
-
- void patch(ApplyStrategy context, NewInstance newInstance);
-
- void patch(ApplyStrategy context, InvokeMethod invoke);
-
- void patch(ApplyStrategy context, InstanceGet instanceGet);
-
- void patch(ApplyStrategy context, StaticGet staticGet);
-
- void patch(ApplyStrategy context, InitClass initClass);
-
- void patch(ApplyStrategy context, Argument argument);
- }
-
- // No-op strategy.
- static final Strategy NoOp =
- new Strategy() {
- @Override
- public LambdaGroup group() {
- return null;
- }
-
- @Override
- public boolean isValidInstanceFieldWrite(CodeProcessor context, DexField field) {
- return false;
- }
-
- @Override
- public boolean isValidInstanceFieldRead(CodeProcessor context, DexField field) {
- return false;
- }
-
- @Override
- public boolean isValidStaticFieldWrite(CodeProcessor context, DexField field) {
- return false;
- }
-
- @Override
- public boolean isValidStaticFieldRead(CodeProcessor context, DexField field) {
- return false;
- }
-
- @Override
- public boolean isValidInvoke(CodeProcessor context, InvokeMethod invoke) {
- return false;
- }
-
- @Override
- public boolean isValidNewInstance(CodeProcessor context, NewInstance invoke) {
- return false;
- }
-
- @Override
- public boolean isValidInitClass(CodeProcessor context, DexType clazz) {
- return false;
- }
-
- @Override
- public boolean isValidHolder(CodeProcessor context, DexType holder) {
- return false;
- }
-
- @Override
- public void patch(ApplyStrategy context, NewInstance newInstance) {
- throw new Unreachable();
- }
-
- @Override
- public void patch(ApplyStrategy context, InvokeMethod invoke) {
- throw new Unreachable();
- }
-
- @Override
- public void patch(ApplyStrategy context, InstanceGet instanceGet) {
- throw new Unreachable();
- }
-
- @Override
- public void patch(ApplyStrategy context, StaticGet staticGet) {
- throw new Unreachable();
- }
-
- @Override
- public void patch(ApplyStrategy context, InitClass initClass) {
- throw new Unreachable();
- }
-
- @Override
- public void patch(ApplyStrategy context, Argument argument) {
- throw new Unreachable();
- }
- };
-
- public final AppView<AppInfoWithLiveness> appView;
- public final DexItemFactory factory;
- public final Kotlin kotlin;
-
- // Defines a factory providing a strategy for a lambda type, returns
- // NoOp strategy if the type is not a lambda.
- private final Function<DexType, Strategy> strategyProvider;
-
- // Visitor for lambda type references seen in unexpected places. Either
- // invalidates the lambda or asserts depending on the processing phase.
- private final LambdaTypeVisitor lambdaChecker;
-
- // Specify the context of the current instruction: method/code/blocks/instructions.
- public final ProgramMethod method;
- public final IRCode code;
- public final ListIterator<BasicBlock> blocks;
- private InstructionListIterator instructions;
-
- // The inlining context (caller), if any.
- private final ProgramMethod context;
-
- CodeProcessor(
- AppView<AppInfoWithLiveness> appView,
- Function<DexType, Strategy> strategyProvider,
- LambdaTypeVisitor lambdaChecker,
- ProgramMethod method,
- IRCode code) {
- this(appView, strategyProvider, lambdaChecker, method, code, null);
- }
-
- CodeProcessor(
- AppView<AppInfoWithLiveness> appView,
- Function<DexType, Strategy> strategyProvider,
- LambdaTypeVisitor lambdaChecker,
- ProgramMethod method,
- IRCode code,
- ProgramMethod context) {
- this.appView = appView;
- this.strategyProvider = strategyProvider;
- this.factory = appView.dexItemFactory();
- this.kotlin = factory.kotlin;
- this.lambdaChecker = lambdaChecker;
- this.method = method;
- this.code = code;
- this.blocks = code.listIterator();
- this.context = context;
- }
-
- public final InstructionListIterator instructions() {
- assert instructions != null;
- return instructions;
- }
-
- void processCode() {
- while (blocks.hasNext()) {
- BasicBlock block = blocks.next();
- instructions = block.listIterator(code);
- while (instructions.hasNext()) {
- instructions.next().accept(this);
- }
- }
- }
-
- private boolean shouldRewrite(DexField field) {
- return shouldRewrite(field.holder);
- }
-
- private boolean shouldRewrite(DexMethod method) {
- return shouldRewrite(method.holder);
- }
-
- private boolean shouldRewrite(DexType type) {
- // Rewrite references to lambda classes if we are outside the class.
- return type != (context != null ? context : method).getHolderType();
- }
-
- @Override
- public Void handleInvoke(Invoke invoke) {
- if (invoke.isInvokeNewArray()) {
- lambdaChecker.accept(invoke.asInvokeNewArray().getReturnType());
- return null;
- }
- if (invoke.isInvokeMultiNewArray()) {
- lambdaChecker.accept(invoke.asInvokeMultiNewArray().getReturnType());
- return null;
- }
- if (invoke.isInvokeCustom()) {
- lambdaChecker.accept(invoke.asInvokeCustom().getCallSite());
- return null;
- }
-
- InvokeMethod invokeMethod = invoke.asInvokeMethod();
- Strategy strategy = strategyProvider.apply(invokeMethod.getInvokedMethod().holder);
- if (strategy.isValidInvoke(this, invokeMethod)) {
- // Invalidate signature, there still should not be lambda references.
- lambdaChecker.accept(invokeMethod.getInvokedMethod().proto);
- // Only rewrite references to lambda classes if we are outside the class.
- if (shouldRewrite(invokeMethod.getInvokedMethod())) {
- process(strategy, invokeMethod);
- }
- return null;
- }
-
- // For the rest invalidate any references.
- if (invoke.isInvokePolymorphic()) {
- lambdaChecker.accept(invoke.asInvokePolymorphic().getProto());
- }
- lambdaChecker.accept(invokeMethod.getInvokedMethod(), null);
- return null;
- }
-
- @Override
- public Void visit(NewInstance newInstance) {
- Strategy strategy = strategyProvider.apply(newInstance.clazz);
- if (strategy.isValidNewInstance(this, newInstance)) {
- // Only rewrite references to lambda classes if we are outside the class.
- if (shouldRewrite(newInstance.clazz)) {
- process(strategy, newInstance);
- }
- }
- return null;
- }
-
- @Override
- public Void visit(CheckCast checkCast) {
- lambdaChecker.accept(checkCast.getType());
- return null;
- }
-
- @Override
- public Void visit(NewArrayEmpty newArrayEmpty) {
- lambdaChecker.accept(newArrayEmpty.type);
- return null;
- }
-
- @Override
- public Void visit(ConstClass constClass) {
- lambdaChecker.accept(constClass.getValue());
- return null;
- }
-
- @Override
- public Void visit(ConstMethodType constMethodType) {
- lambdaChecker.accept(constMethodType.getValue());
- return null;
- }
-
- @Override
- public Void visit(ConstMethodHandle constMethodHandle) {
- lambdaChecker.accept(constMethodHandle.getValue());
- return null;
- }
-
- @Override
- public Void visit(InstanceGet instanceGet) {
- DexField field = instanceGet.getField();
- Strategy strategy = strategyProvider.apply(field.holder);
- if (strategy.isValidInstanceFieldRead(this, field)) {
- if (shouldRewrite(field)) {
- // Only rewrite references to lambda classes if we are outside the class.
- process(strategy, instanceGet);
- }
- } else {
- lambdaChecker.accept(field.type);
- }
-
- // We avoid fields with type being lambda class, it is possible for
- // a lambda to capture another lambda, but we don't support it for now.
- lambdaChecker.accept(field.type);
- return null;
- }
-
- @Override
- public Void visit(InstancePut instancePut) {
- DexField field = instancePut.getField();
- Strategy strategy = strategyProvider.apply(field.holder);
- if (strategy.isValidInstanceFieldWrite(this, field)) {
- if (shouldRewrite(field)) {
- // Only rewrite references to lambda classes if we are outside the class.
- process(strategy, instancePut);
- }
- } else {
- lambdaChecker.accept(field.type);
- }
-
- // We avoid fields with type being lambda class, it is possible for
- // a lambda to capture another lambda, but we don't support it for now.
- lambdaChecker.accept(field.type);
- return null;
- }
-
- @Override
- public Void visit(StaticGet staticGet) {
- DexField field = staticGet.getField();
- Strategy strategy = strategyProvider.apply(field.holder);
- if (strategy.isValidStaticFieldRead(this, field)) {
- if (shouldRewrite(field)) {
- // Only rewrite references to lambda classes if we are outside the class.
- process(strategy, staticGet);
- }
- } else {
- lambdaChecker.accept(field.type);
- lambdaChecker.accept(field.holder);
- }
- return null;
- }
-
- @Override
- public Void visit(StaticPut staticPut) {
- DexField field = staticPut.getField();
- Strategy strategy = strategyProvider.apply(field.holder);
- if (strategy.isValidStaticFieldWrite(this, field)) {
- if (shouldRewrite(field)) {
- // Only rewrite references to lambda classes if we are outside the class.
- process(strategy, staticPut);
- }
- } else {
- lambdaChecker.accept(field.type);
- lambdaChecker.accept(field.holder);
- }
- return null;
- }
-
- @Override
- public Void visit(InitClass initClass) {
- DexType clazz = initClass.getClassValue();
- Strategy strategy = strategyProvider.apply(clazz);
- if (strategy.isValidInitClass(this, clazz)) {
- if (shouldRewrite(clazz)) {
- // Only rewrite references to lambda classes if we are outside the class.
- process(strategy, initClass);
- }
- } else {
- lambdaChecker.accept(clazz);
- }
- return null;
- }
-
- @Override
- public Void visit(Argument instruction) {
- if (instruction.outValue() != code.getThis()) {
- return null;
- }
- Strategy strategy = strategyProvider.apply(method.getHolderType());
- if (strategy.isValidHolder(this, method.getHolderType())) {
- if (shouldRewrite(method.getHolderType())) {
- process(strategy, instruction);
- }
- }
- return null;
- }
-
- abstract void process(Strategy strategy, InvokeMethod invokeMethod);
-
- abstract void process(Strategy strategy, NewInstance newInstance);
-
- abstract void process(Strategy strategy, InstancePut instancePut);
-
- abstract void process(Strategy strategy, InstanceGet instanceGet);
-
- abstract void process(Strategy strategy, StaticPut staticPut);
-
- abstract void process(Strategy strategy, StaticGet staticGet);
-
- abstract void process(Strategy strategy, InitClass initClass);
-
- abstract void process(Strategy strategy, Argument argument);
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
deleted file mode 100644
index cc01f83..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda;
-
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
-import com.android.tools.r8.ir.optimize.lambda.CodeProcessor.Strategy;
-import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.shaking.MainDexClasses;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.ThrowingConsumer;
-import com.google.common.collect.Lists;
-import com.google.common.io.BaseEncoding;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
-
-// Represents a group of lambda classes which potentially can be represented
-// by the same lambda _group_ class. Each lambda class inside the group is
-// assigned an integer id.
-//
-// NOTE: access to lambdas in lambda group is NOT thread-safe.
-public abstract class LambdaGroup {
- public final LambdaGroupId id;
-
- // Lambda group class name. Is intended to be stable and uniques.
- // In current implementation is generated in following way:
- // <optional-package>.-$$LambdaGroup$<HASH>
- // with HASH generated based on names of the lambda class names
- // of lambdas included in the group.
- private DexType classType;
-
- // Maps lambda classes belonging to the group into the index inside the
- // group. Note usage of linked hash map to keep insertion ordering stable.
- private final Map<DexType, LambdaInfo> lambdas = new LinkedHashMap<>();
-
- public static class LambdaInfo {
- public int id;
- public final DexProgramClass clazz;
-
- LambdaInfo(int id, DexProgramClass clazz) {
- this.id = id;
- this.clazz = clazz;
- }
-
- public DexProgramClass getLambdaClass() {
- return clazz;
- }
- }
-
- public LambdaGroup(LambdaGroupId id) {
- this.id = id;
- }
-
- public final DexType getGroupClassType() {
- assert classType != null;
- return classType;
- }
-
- public final int size() {
- return lambdas.size();
- }
-
- public final void forEachLambda(Consumer<LambdaInfo> action) {
- assert verifyLambdaIds(false);
- for (LambdaInfo info : lambdas.values()) {
- action.accept(info);
- }
- }
-
- public final boolean anyLambda(Predicate<LambdaInfo> predicate) {
- assert verifyLambdaIds(false);
- for (LambdaInfo info : lambdas.values()) {
- if (predicate.test(info)) {
- return true;
- }
- }
- return false;
- }
-
- final boolean shouldAddToMainDex(AppView<?> appView) {
- // We add the group class to main index if any of the
- // lambda classes it replaces is added to main index.
- MainDexClasses mainDexClasses = appView.appInfo().getMainDexClasses();
- for (LambdaInfo info : lambdas.values()) {
- if (mainDexClasses.contains(info.getLambdaClass())) {
- return true;
- }
- }
- return false;
- }
-
- public final boolean containsLambda(DexType lambda) {
- return lambdas.containsKey(lambda);
- }
-
- public final int lambdaId(DexType lambda) {
- assert lambdas.containsKey(lambda);
- return lambdas.get(lambda).id;
- }
-
- protected final List<DexEncodedField> lambdaCaptureFields(DexType lambda) {
- assert lambdas.containsKey(lambda);
- return lambdas.get(lambda).clazz.instanceFields();
- }
-
- protected final DexEncodedField lambdaSingletonField(DexType lambda) {
- assert lambdas.containsKey(lambda);
- List<DexEncodedField> fields = lambdas.get(lambda).clazz.staticFields();
- assert fields.size() < 2;
- return fields.size() == 0 ? null : fields.get(0);
- }
-
- // Contains less than 2 elements?
- final boolean isTrivial() {
- return lambdas.size() < 2;
- }
-
- final void add(DexProgramClass lambda) {
- assert !lambdas.containsKey(lambda.type);
- lambdas.put(lambda.type, new LambdaInfo(lambdas.size(), lambda));
- }
-
- final void remove(DexType lambda) {
- assert lambdas.containsKey(lambda);
- lambdas.remove(lambda);
- }
-
- final void compact() {
- assert verifyLambdaIds(false);
- int lastUsed = -1;
- int lastSeen = -1;
- for (Entry<DexType, LambdaInfo> entry : lambdas.entrySet()) {
- int index = entry.getValue().id;
- assert lastUsed <= lastSeen && lastSeen < index;
- lastUsed++;
- lastSeen = index;
- if (lastUsed < index) {
- entry.getValue().id = lastUsed;
- }
- }
- assert verifyLambdaIds(true);
- }
-
- public abstract Strategy getCodeStrategy();
-
- public abstract ThrowingConsumer<DexClass, LambdaStructureError> lambdaClassValidator(
- Kotlin kotlin, AppInfoWithClassHierarchy appInfo);
-
- // Package for a lambda group class to be created in.
- protected abstract String getTypePackage();
-
- protected abstract String getGroupSuffix();
-
- final DexProgramClass synthesizeClass(
- AppView<? extends AppInfoWithClassHierarchy> appView, OptimizationFeedback feedback) {
- assert classType == null;
- assert verifyLambdaIds(true);
- List<LambdaInfo> lambdas = Lists.newArrayList(this.lambdas.values());
- classType =
- appView
- .dexItemFactory()
- .createType(
- "L"
- + getTypePackage()
- + "-$$LambdaGroup$"
- + getGroupSuffix()
- + createHash(lambdas)
- + ";");
- return getBuilder(appView.dexItemFactory(), appView.options())
- .synthesizeClass(appView, feedback);
- }
-
- protected abstract LambdaGroupClassBuilder<? extends LambdaGroup> getBuilder(
- DexItemFactory factory, InternalOptions options);
-
- private String createHash(List<LambdaInfo> lambdas) {
- try {
- ByteArrayOutputStream bytes = new ByteArrayOutputStream();
- ObjectOutputStream out = new ObjectOutputStream(bytes);
-
- // We will generate SHA-1 hash of the list of lambda classes represented in the group.
- for (LambdaInfo lambda : lambdas) {
- DexString descriptor = lambda.clazz.type.descriptor;
- out.writeInt(descriptor.size); // To avoid same-prefix problem
- out.write(descriptor.content);
- }
- out.close();
-
- MessageDigest digest = MessageDigest.getInstance("SHA-1");
- digest.update(bytes.toByteArray());
- return BaseEncoding.base64Url().omitPadding().encode(digest.digest());
- } catch (NoSuchAlgorithmException | IOException ex) {
- throw new Unreachable("Cannot get SHA-1 message digest");
- }
- }
-
- private boolean verifyLambdaIds(boolean strict) {
- int previous = -1;
- for (LambdaInfo info : lambdas.values()) {
- assert strict ? (previous + 1) == info.id : previous < info.id;
- previous = info.id;
- }
- return true;
- }
-
- public static class LambdaStructureError extends Exception {
- final boolean reportable;
-
- public LambdaStructureError(String cause) {
- this(cause, true);
- }
-
- public LambdaStructureError(String cause, boolean reportable) {
- super(cause);
- this.reportable = reportable;
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
deleted file mode 100644
index 92f0972..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda;
-
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClassAccessFlags;
-import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
-import com.android.tools.r8.graph.EnclosingMethodAttribute;
-import com.android.tools.r8.graph.GenericSignature.ClassSignature;
-import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
-import com.android.tools.r8.origin.SynthesizedOrigin;
-import java.util.Collections;
-import java.util.List;
-
-// Encapsulates lambda group class building logic and separates
-// it from the rest of lambda group functionality.
-public abstract class LambdaGroupClassBuilder<T extends LambdaGroup> {
- protected final T group;
- protected final DexItemFactory factory;
- protected final String origin;
-
- protected LambdaGroupClassBuilder(T group, DexItemFactory factory, String origin) {
- this.group = group;
- this.factory = factory;
- this.origin = origin;
- }
-
- public final DexProgramClass synthesizeClass(
- AppView<? extends AppInfoWithClassHierarchy> appView, OptimizationFeedback feedback) {
- DexType groupClassType = group.getGroupClassType();
- DexType superClassType = getSuperClassType();
- return new DexProgramClass(
- groupClassType,
- null,
- new SynthesizedOrigin(origin, getClass()),
- buildAccessFlags(),
- superClassType,
- buildInterfaces(),
- factory.createString(origin),
- null,
- Collections.emptyList(),
- buildEnclosingMethodAttribute(),
- buildInnerClasses(),
- buildClassSignature(),
- DexAnnotationSet.empty(),
- buildStaticFields(appView, feedback),
- buildInstanceFields(),
- buildDirectMethods(),
- buildVirtualMethods(),
- factory.getSkipNameValidationForTesting(),
- // The name of the class is based on the hash of the content.
- DexProgramClass::checksumFromType);
- }
-
- protected abstract DexType getSuperClassType();
-
- protected abstract ClassAccessFlags buildAccessFlags();
-
- protected abstract EnclosingMethodAttribute buildEnclosingMethodAttribute();
-
- protected abstract List<InnerClassAttribute> buildInnerClasses();
-
- protected abstract ClassSignature buildClassSignature();
-
- protected abstract DexEncodedMethod[] buildVirtualMethods();
-
- protected abstract DexEncodedMethod[] buildDirectMethods();
-
- protected abstract DexEncodedField[] buildInstanceFields();
-
- protected abstract DexEncodedField[] buildStaticFields(
- AppView<? extends AppInfoWithClassHierarchy> appView, OptimizationFeedback feedback);
-
- protected abstract DexTypeList buildInterfaces();
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupId.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupId.java
deleted file mode 100644
index 2c31541..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupId.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda;
-
-// Represents a lambda group identifier uniquely identifying the groups
-// of potentially mergeable lambdas.
-//
-// Implements hashCode/equals in a way that guarantees that if two lambda
-// classes has equal ids they belong to the same lambda group.
-public interface LambdaGroupId {
- LambdaGroup createGroup();
-
- @Override
- int hashCode();
-
- @Override
- boolean equals(Object obj);
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
deleted file mode 100644
index 5bccf4d4..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ /dev/null
@@ -1,738 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda;
-
-import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexApplication.Builder;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassAndMethod;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.GraphLens;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.ResolutionResult;
-import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
-import com.android.tools.r8.ir.analysis.type.DestructivePhiTypeUpdater;
-import com.android.tools.r8.ir.code.Argument;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.InitClass;
-import com.android.tools.r8.ir.code.InstanceGet;
-import com.android.tools.r8.ir.code.InstancePut;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.InvokeMethod;
-import com.android.tools.r8.ir.code.InvokeVirtual;
-import com.android.tools.r8.ir.code.NewInstance;
-import com.android.tools.r8.ir.code.Phi;
-import com.android.tools.r8.ir.code.StaticGet;
-import com.android.tools.r8.ir.code.StaticPut;
-import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.conversion.MethodProcessor;
-import com.android.tools.r8.ir.optimize.Inliner;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.Inliner.InliningInfo;
-import com.android.tools.r8.ir.optimize.info.FieldOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedback.OptimizationInfoFixer;
-import com.android.tools.r8.ir.optimize.inliner.InliningIRProvider;
-import com.android.tools.r8.ir.optimize.lambda.CodeProcessor.Strategy;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroup.LambdaStructureError;
-import com.android.tools.r8.ir.optimize.lambda.kotlin.KotlinLambdaGroupIdFactory;
-import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
-import com.android.tools.r8.shaking.ProguardConfiguration;
-import com.android.tools.r8.utils.SetUtils;
-import com.android.tools.r8.utils.StringDiagnostic;
-import com.android.tools.r8.utils.ThreadUtils;
-import com.android.tools.r8.utils.ThrowingConsumer;
-import com.android.tools.r8.utils.Timing;
-import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
-import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
-import com.google.common.collect.Sets;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Deque;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.function.Function;
-
-// Merging lambda classes into single lambda group classes. There are three flavors
-// of lambdas we are dealing with:
-// (a) lambda classes synthesized in desugaring, handles java lambdas
-// (b) k-style lambda classes synthesized by kotlin compiler
-// (c) j-style lambda classes synthesized by kotlin compiler
-//
-// Lambda merging is potentially applicable to all three of them, but
-// current implementation deals with both k- and j-style lambdas.
-//
-// In general we merge lambdas in 5 phases:
-// 1. collect all lambdas and compute group candidates. we do it synchronously
-// and ensure that the order of lambda groups and lambdas inside each group
-// is stable.
-// 2. analyze usages of lambdas and exclude lambdas with unexpected usage
-// NOTE: currently we consider *all* usages outside the code invalid
-// so we only need to patch method code when replacing the lambda class.
-// 3. exclude (invalidate) all lambda classes with usages we don't understand
-// or support, compact the remaining lambda groups, remove trivial groups
-// with less that 2 lambdas.
-// 4. replace lambda valid/supported class constructions with references to
-// lambda group classes.
-// 5. synthesize group lambda classes.
-//
-public final class LambdaMerger {
-
- private abstract static class Mode {
-
- void rewriteCode(
- ProgramMethod method,
- IRCode code,
- Inliner inliner,
- ProgramMethod context,
- InliningIRProvider provider) {}
-
- void analyzeCode(ProgramMethod method, IRCode code) {}
- }
-
- private class AnalyzeMode extends Mode {
-
- @Override
- void analyzeCode(ProgramMethod method, IRCode code) {
- new AnalysisStrategy(method, code).processCode();
- }
- }
-
- private class ApplyMode extends Mode {
-
- private final Map<DexProgramClass, LambdaGroup> lambdaGroups;
- private final LambdaMergerOptimizationInfoFixer optimizationInfoFixer;
-
- ApplyMode(
- Map<DexProgramClass, LambdaGroup> lambdaGroups,
- LambdaMergerOptimizationInfoFixer optimizationInfoFixer) {
- this.lambdaGroups = lambdaGroups;
- this.optimizationInfoFixer = optimizationInfoFixer;
- }
-
- @Override
- void rewriteCode(
- ProgramMethod method,
- IRCode code,
- Inliner inliner,
- ProgramMethod context,
- InliningIRProvider provider) {
- LambdaGroup lambdaGroup = lambdaGroups.get(method.getHolder());
- if (lambdaGroup == null) {
- // Only rewrite the methods that have not been synthesized for the lambda group classes.
- new ApplyStrategy(method, code, context, optimizationInfoFixer).processCode();
- return;
- }
-
- if (method.getDefinition().isInitializer()) {
- // Should not require rewriting.
- return;
- }
-
- assert method.getDefinition().isNonPrivateVirtualMethod();
- assert context == null;
-
- Map<InvokeVirtual, InliningInfo> invokesToInline = new IdentityHashMap<>();
- for (InvokeVirtual invoke : code.<InvokeVirtual>instructions(Instruction::isInvokeVirtual)) {
- DexMethod invokedMethod = invoke.getInvokedMethod();
- DexType holder = invokedMethod.holder;
- if (lambdaGroup.containsLambda(holder)) {
- // TODO(b/150685763): Check if we can use simpler lookup.
- ResolutionResult resolution = appView.appInfo().resolveMethodOnClass(invokedMethod);
- assert resolution.isSingleResolution();
- ProgramMethod singleTarget =
- resolution.asSingleResolution().getResolutionPair().asProgramMethod();
- assert singleTarget != null;
- invokesToInline.put(invoke, new InliningInfo(singleTarget, singleTarget.getHolderType()));
- }
- }
-
- assert invokesToInline.size() > 1
- || appView.options().testing.verificationSizeLimitInBytesOverride > -1;
-
- inliner.performForcedInlining(method, code, invokesToInline, provider, Timing.empty());
- }
- }
-
- // Maps lambda into a group, only contains lambdas we decided to merge.
- // NOTE: needs synchronization.
- private final Map<DexType, LambdaGroup> lambdas = new IdentityHashMap<>();
- // We use linked map to ensure stable ordering of the groups
- // when they are processed sequentially.
- // NOTE: needs synchronization.
- private final Map<LambdaGroupId, LambdaGroup> groups = new LinkedHashMap<>();
-
- // Since invalidating lambdas may happen concurrently we don't remove invalidated lambdas
- // from groups (and `lambdas`) right away since the ordering may be important. Instead we
- // collect invalidated lambdas and remove them from groups after analysis is done.
- private final Set<DexType> invalidatedLambdas = Sets.newConcurrentHashSet();
-
- // Methods which need to be patched to reference lambda group classes instead of the
- // original lambda classes. The number of methods is expected to be small since there
- // is a 1:1 relation between lambda and method it is defined in (unless such a method
- // was inlined by either kotlinc or r8).
- //
- // Note that we don't track precisely lambda -> method mapping, so it may happen that
- // we mark a method for further processing, and then invalidate the only lambda referenced
- // from it. In this case we will reprocess method that does not need patching, but it
- // should not be happening very frequently and we ignore possible overhead.
- private final LongLivedProgramMethodSetBuilder<SortedProgramMethodSet> methodsToReprocess =
- LongLivedProgramMethodSetBuilder.createForSortedSet();
-
- private final AppView<AppInfoWithLiveness> appView;
- private final Kotlin kotlin;
- private final DiagnosticsHandler reporter;
-
- private Mode mode;
-
- // Lambda visitor invalidating lambdas it sees.
- private final LambdaTypeVisitor lambdaInvalidator;
- // Lambda visitor throwing Unreachable on each lambdas it sees.
- private final LambdaTypeVisitor lambdaChecker;
-
- public LambdaMerger(AppView<AppInfoWithLiveness> appView) {
- DexItemFactory factory = appView.dexItemFactory();
- this.appView = appView;
- this.kotlin = factory.kotlin;
- this.reporter = appView.options().reporter;
-
- this.lambdaInvalidator =
- new LambdaTypeVisitor(factory, this::isMergeableLambda, this::invalidateLambda);
- this.lambdaChecker =
- new LambdaTypeVisitor(
- factory,
- this::isMergeableLambda,
- type -> {
- throw new Unreachable("Unexpected lambda " + type.toSourceString());
- });
- }
-
- private void invalidateLambda(DexType lambda) {
- invalidatedLambdas.add(lambda);
- }
-
- private synchronized boolean isMergeableLambda(DexType lambda) {
- return lambdas.containsKey(lambda);
- }
-
- private synchronized LambdaGroup getLambdaGroup(DexType lambda) {
- return lambdas.get(lambda);
- }
-
- private synchronized void queueForProcessing(ProgramMethod method) {
- methodsToReprocess.add(method);
- }
-
- // Collect all group candidates and assign unique lambda ids inside each group.
- // We do this before methods are being processed to guarantee stable order of
- // lambdas inside each group.
- public final void collectGroupCandidates(DexApplication app) {
- // Collect lambda groups.
- app.classes().stream()
- .filter(cls -> !appView.appInfo().isPinned(cls.type))
- .filter(
- cls ->
- appView.testing().kotlinLambdaMergerFactoryForClass.apply(cls) != null
- && KotlinLambdaGroupIdFactory.hasValidAnnotations(kotlin, cls)
- && !appView.appInfo().getClassToFeatureSplitMap().isInFeature(cls))
- .sorted(Comparator.comparing(DexClass::getType)) // Ensure stable ordering.
- .forEachOrdered(
- lambda -> {
- try {
- KotlinLambdaGroupIdFactory lambdaGroupIdFactory =
- appView.testing().kotlinLambdaMergerFactoryForClass.apply(lambda);
- LambdaGroupId id = lambdaGroupIdFactory.validateAndCreate(appView, kotlin, lambda);
- LambdaGroup group = groups.computeIfAbsent(id, LambdaGroupId::createGroup);
- group.add(lambda);
- lambdas.put(lambda.type, group);
- } catch (LambdaStructureError error) {
- // Intentionally empty.
- }
- });
-
- // Remove trivial groups.
- removeTrivialLambdaGroups();
-
- assert mode == null;
- mode = new AnalyzeMode();
- }
-
- /**
- * Is called by IRConverter::rewriteCode. Performs different actions depending on the current
- * mode.
- *
- * <ol>
- * <li>in ANALYZE mode analyzes invalid usages of lambda classes inside the method code,
- * invalidated such lambda classes, collects methods that need to be patched.
- * <li>in APPLY mode does nothing.
- * </ol>
- */
- public final void analyzeCode(ProgramMethod method, IRCode code) {
- if (mode != null) {
- mode.analyzeCode(method, code);
- }
- }
-
- /**
- * Is called by IRConverter::rewriteCode. Performs different actions depending on the current
- * mode.
- *
- * <ol>
- * <li>in ANALYZE mode does nothing.
- * <li>in APPLY mode patches the code to use lambda group classes, also asserts that there are
- * no more invalid lambda class references.
- * </ol>
- */
- public final void rewriteCode(
- ProgramMethod method, IRCode code, Inliner inliner, MethodProcessor methodProcessor) {
- if (mode != null) {
- mode.rewriteCode(
- code.context(),
- code,
- inliner,
- null,
- new InliningIRProvider(appView, method, code, methodProcessor));
- }
- }
-
- /**
- * Similar to {@link #rewriteCode(ProgramMethod, IRCode, Inliner, MethodProcessor)}, but for
- * rewriting code for inlining. The {@param context} is the caller that {@param method} is being
- * inlined into.
- */
- public final void rewriteCodeForInlining(
- ProgramMethod method, IRCode code, ProgramMethod context, InliningIRProvider provider) {
- if (mode != null) {
- mode.rewriteCode(method, code, null, context, provider);
- }
- }
-
- public final void applyLambdaClassMapping(
- DexApplication app,
- IRConverter converter,
- OptimizationFeedback feedback,
- Builder<?> builder,
- ExecutorService executorService,
- GraphLens appliedGraphLens)
- throws ExecutionException {
- if (lambdas.isEmpty()) {
- appView.setHorizontallyMergedLambdaClasses(HorizontallyMergedLambdaClasses.empty());
- return;
- }
-
- // Analyse references from program classes. We assume that this optimization
- // is only used for full program analysis and there are no classpath classes.
- ThreadUtils.processItems(app.classes(), this::analyzeClass, executorService);
-
- // Analyse more complex aspects of lambda classes including method code.
- analyzeLambdaClassesStructure(executorService);
-
- // Remove invalidated lambdas, compact groups to ensure
- // sequential lambda ids, create group lambda classes.
- BiMap<LambdaGroup, DexProgramClass> lambdaGroupsClasses = finalizeLambdaGroups(feedback);
-
- // Fixup optimization info to ensure that the optimization info does not refer to any merged
- // lambdas.
- LambdaMergerOptimizationInfoFixer optimizationInfoFixer =
- new LambdaMergerOptimizationInfoFixer(lambdaGroupsClasses);
- feedback.fixupOptimizationInfos(appView, executorService, optimizationInfoFixer);
-
- // Switch to APPLY strategy.
- this.mode = new ApplyMode(lambdaGroupsClasses.inverse(), optimizationInfoFixer);
-
- FieldAccessInfoCollectionModifier.Builder fieldAccessInfoCollectionModifierBuilder =
- FieldAccessInfoCollectionModifier.builder();
-
- // Add synthesized lambda group classes to the builder.
- for (Entry<LambdaGroup, DexProgramClass> entry : lambdaGroupsClasses.entrySet()) {
- DexProgramClass synthesizedClass = entry.getValue();
- appView
- .appInfo()
- .addSynthesizedClass(synthesizedClass, entry.getKey().shouldAddToMainDex(appView));
- builder.addSynthesizedClass(synthesizedClass);
-
- synthesizedClass.forEachField(
- field ->
- fieldAccessInfoCollectionModifierBuilder
- .recordFieldReadInUnknownContext(field.getReference())
- .recordFieldWriteInUnknownContext(field.getReference()));
-
- // Eventually, we need to process synthesized methods in the lambda group.
- // Otherwise, abstract SynthesizedCode will be flown to Enqueuer.
- // But that process should not see the holder. Otherwise, lambda calls in the main dispatch
- // method became recursive calls via the lens rewriter. They should remain, then inliner
- // will inline methods from mergee lambdas to the main dispatch method.
- // Then, there is a dilemma: other sub optimizations trigger subtype lookup that will throw
- // NPE if it cannot find the holder for this synthesized lambda group.
- // One hack here is to mark those methods `processed` so that the lens rewriter is skipped.
- synthesizedClass.forEachMethod(
- encodedMethod -> encodedMethod.markProcessed(ConstraintWithTarget.NEVER));
- }
-
- // Record field accesses for synthesized fields.
- fieldAccessInfoCollectionModifierBuilder.build().modify(appView);
-
- converter.optimizeSynthesizedClasses(lambdaGroupsClasses.values(), executorService);
-
- // Rewrite lambda class references into lambda group class
- // references inside methods from the processing queue.
- rewriteLambdaReferences(converter, executorService, appliedGraphLens);
- this.mode = null;
-
- appView.setHorizontallyMergedLambdaClasses(new HorizontallyMergedLambdaClasses(lambdas));
- }
-
- private void analyzeLambdaClassesStructure(ExecutorService service) throws ExecutionException {
- List<Future<?>> futures = new ArrayList<>();
- for (LambdaGroup group : groups.values()) {
- ThrowingConsumer<DexClass, LambdaStructureError> validator =
- group.lambdaClassValidator(kotlin, appView.appInfo());
- group.forEachLambda(
- info ->
- futures.add(
- service.submit(
- () -> {
- try {
- validator.accept(info.clazz);
- } catch (LambdaStructureError error) {
- ProguardConfiguration proguardConfiguration =
- appView.options().getProguardConfiguration();
- if (error.reportable
- && !proguardConfiguration
- .getDontNotePatterns()
- .matches(info.clazz.getType())) {
- reporter.info(
- new StringDiagnostic(
- "Unexpected Kotlin lambda structure ["
- + info.clazz.type.toSourceString()
- + "]: "
- + error.getMessage()));
- }
- invalidateLambda(info.clazz.type);
- }
- })));
- }
- ThreadUtils.awaitFutures(futures);
- }
-
- private BiMap<LambdaGroup, DexProgramClass> finalizeLambdaGroups(OptimizationFeedback feedback) {
- for (DexType lambda : invalidatedLambdas) {
- LambdaGroup group = lambdas.get(lambda);
- assert group != null;
- lambdas.remove(lambda);
- group.remove(lambda);
- }
- invalidatedLambdas.clear();
-
- // Remove new trivial lambdas.
- removeTrivialLambdaGroups();
-
- // Compact lambda groups, synthesize lambda group classes.
- BiMap<LambdaGroup, DexProgramClass> result = HashBiMap.create();
- for (LambdaGroup group : groups.values()) {
- assert !group.isTrivial() : "No trivial group is expected here.";
- group.compact();
- DexProgramClass lambdaGroupClass = group.synthesizeClass(appView, feedback);
- result.put(group, lambdaGroupClass);
- }
- return result;
- }
-
- private void removeTrivialLambdaGroups() {
- Iterator<Entry<LambdaGroupId, LambdaGroup>> iterator = groups.entrySet().iterator();
- while (iterator.hasNext()) {
- Entry<LambdaGroupId, LambdaGroup> group = iterator.next();
- if (group.getValue().isTrivial()) {
- iterator.remove();
- assert group.getValue().size() < 2;
- group.getValue().forEachLambda(info -> this.lambdas.remove(info.clazz.type));
- }
- }
- }
-
- private void rewriteLambdaReferences(
- IRConverter converter, ExecutorService executorService, GraphLens appliedGraphLens)
- throws ExecutionException {
- if (methodsToReprocess.isEmpty()) {
- return;
- }
- SortedProgramMethodSet methods = methodsToReprocess.build(appView, appliedGraphLens);
- converter.processMethodsConcurrently(methods, executorService);
- assert methods.stream()
- .map(DexClassAndMethod::getDefinition)
- .allMatch(DexEncodedMethod::isProcessed);
- }
-
- private void analyzeClass(DexProgramClass clazz) {
- lambdaInvalidator.accept(clazz.superType);
- lambdaInvalidator.accept(clazz.interfaces);
- lambdaInvalidator.accept(clazz.annotations());
-
- for (DexEncodedField field : clazz.staticFields()) {
- lambdaInvalidator.accept(field.annotations());
- if (field.field.type != clazz.type) {
- // Ignore static fields of the same type.
- lambdaInvalidator.accept(field.field, clazz.type);
- }
- }
- for (DexEncodedField field : clazz.instanceFields()) {
- lambdaInvalidator.accept(field.annotations());
- lambdaInvalidator.accept(field.field, clazz.type);
- }
-
- for (DexEncodedMethod method : clazz.methods()) {
- lambdaInvalidator.accept(method.annotations());
- lambdaInvalidator.accept(method.parameterAnnotationsList);
- lambdaInvalidator.accept(method.method, clazz.type);
- }
- }
-
- private Strategy strategyProvider(DexType type) {
- LambdaGroup group = this.getLambdaGroup(type);
- return group != null ? group.getCodeStrategy() : CodeProcessor.NoOp;
- }
-
- private final class AnalysisStrategy extends CodeProcessor {
- private AnalysisStrategy(ProgramMethod method, IRCode code) {
- super(
- LambdaMerger.this.appView,
- LambdaMerger.this::strategyProvider,
- lambdaInvalidator,
- method,
- code);
- }
-
- @Override
- void process(Strategy strategy, InvokeMethod invokeMethod) {
- queueForProcessing(method);
- }
-
- @Override
- void process(Strategy strategy, NewInstance newInstance) {
- queueForProcessing(method);
- }
-
- @Override
- void process(Strategy strategy, InstancePut instancePut) {
- queueForProcessing(method);
- }
-
- @Override
- void process(Strategy strategy, InstanceGet instanceGet) {
- queueForProcessing(method);
- }
-
- @Override
- void process(Strategy strategy, StaticPut staticPut) {
- queueForProcessing(method);
- }
-
- @Override
- void process(Strategy strategy, StaticGet staticGet) {
- queueForProcessing(method);
- }
-
- @Override
- void process(Strategy strategy, InitClass initClass) {
- queueForProcessing(method);
- }
-
- @Override
- void process(Strategy strategy, Argument argument) {
- throw new Unreachable();
- }
- }
-
- public final class ApplyStrategy extends CodeProcessor {
-
- private final LambdaMergerOptimizationInfoFixer optimizationInfoFixer;
-
- private final Set<Value> typeAffectedValues = Sets.newIdentityHashSet();
-
- private ApplyStrategy(
- ProgramMethod method,
- IRCode code,
- ProgramMethod context,
- LambdaMergerOptimizationInfoFixer optimizationInfoFixer) {
- super(
- LambdaMerger.this.appView,
- LambdaMerger.this::strategyProvider,
- lambdaChecker,
- method,
- code,
- context);
- this.optimizationInfoFixer = optimizationInfoFixer;
- }
-
- public void recordTypeHasChanged(Value value) {
- for (Value affectedValue : value.affectedValues()) {
- if (typeMayHaveChanged(affectedValue)) {
- typeAffectedValues.add(affectedValue);
- }
- }
- }
-
- @Override
- void processCode() {
- super.processCode();
-
- if (typeAffectedValues.isEmpty()) {
- return;
- }
-
- // Find all the transitively type affected values.
- Set<Value> transitivelyTypeAffectedValues = SetUtils.newIdentityHashSet(typeAffectedValues);
- Deque<Value> worklist = new ArrayDeque<>(typeAffectedValues);
- while (!worklist.isEmpty()) {
- Value value = worklist.pop();
- assert typeMayHaveChanged(value);
- assert transitivelyTypeAffectedValues.contains(value);
-
- for (Value affectedValue : value.affectedValues()) {
- if (typeMayHaveChanged(affectedValue)
- && transitivelyTypeAffectedValues.add(affectedValue)) {
- worklist.add(affectedValue);
- }
- }
- }
-
- // Update the types of these values if they refer to obsolete types. This is needed to be
- // able to propagate the type information correctly, since lambda merging is neither a
- // narrowing nor a widening.
- for (Value value : transitivelyTypeAffectedValues) {
- value.setType(value.getType().fixupClassTypeReferences(optimizationInfoFixer, appView));
- }
-
- // Filter out the type affected phis and destructively update the type of the phis. This is
- // needed because narrowing does not work in presence of cyclic phis.
- Set<Phi> typeAffectedPhis = Sets.newIdentityHashSet();
- for (Value typeAffectedValue : transitivelyTypeAffectedValues) {
- if (typeAffectedValue.isPhi()) {
- typeAffectedPhis.add(typeAffectedValue.asPhi());
- }
- }
- if (!typeAffectedPhis.isEmpty()) {
- new DestructivePhiTypeUpdater(appView, optimizationInfoFixer)
- .recomputeAndPropagateTypes(code, typeAffectedPhis);
- }
- assert code.verifyTypes(appView);
- }
-
- private boolean typeMayHaveChanged(Value value) {
- return value.isPhi() || !value.definition.hasInvariantOutType();
- }
-
- @Override
- void process(Strategy strategy, InvokeMethod invokeMethod) {
- strategy.patch(this, invokeMethod);
- }
-
- @Override
- void process(Strategy strategy, NewInstance newInstance) {
- strategy.patch(this, newInstance);
- }
-
- @Override
- void process(Strategy strategy, InstancePut instancePut) {
- // Instance put should only appear in lambda class instance constructor,
- // we should never get here since we never rewrite them.
- throw new Unreachable();
- }
-
- @Override
- void process(Strategy strategy, InstanceGet instanceGet) {
- strategy.patch(this, instanceGet);
- }
-
- @Override
- void process(Strategy strategy, StaticPut staticPut) {
- // Static put should only appear in lambda class static initializer,
- // we should never get here since we never rewrite them.
- throw new Unreachable();
- }
-
- @Override
- void process(Strategy strategy, StaticGet staticGet) {
- strategy.patch(this, staticGet);
- }
-
- @Override
- void process(Strategy strategy, InitClass initClass) {
- strategy.patch(this, initClass);
- }
-
- @Override
- void process(Strategy strategy, Argument argument) {
- strategy.patch(this, argument);
- }
- }
-
- private final class LambdaMergerOptimizationInfoFixer
- implements Function<DexType, DexType>, OptimizationInfoFixer {
-
- private final Map<LambdaGroup, DexProgramClass> lambdaGroupsClasses;
-
- LambdaMergerOptimizationInfoFixer(Map<LambdaGroup, DexProgramClass> lambdaGroupsClasses) {
- this.lambdaGroupsClasses = lambdaGroupsClasses;
- }
-
- @Override
- public DexType apply(DexType type) {
- LambdaGroup group = lambdas.get(type);
- if (group != null) {
- DexProgramClass clazz = lambdaGroupsClasses.get(group);
- if (clazz != null) {
- return clazz.type;
- }
- }
- return type;
- }
-
- @Override
- public void fixup(DexEncodedField field) {
- FieldOptimizationInfo optimizationInfo = field.getOptimizationInfo();
- if (optimizationInfo.isMutableFieldOptimizationInfo()) {
- optimizationInfo.asMutableFieldOptimizationInfo().fixupClassTypeReferences(this, appView);
- } else {
- assert optimizationInfo.isDefaultFieldOptimizationInfo();
- }
- }
-
- @Override
- public void fixup(DexEncodedMethod method) {
- MethodOptimizationInfo optimizationInfo = method.getOptimizationInfo();
- if (optimizationInfo.isUpdatableMethodOptimizationInfo()) {
- optimizationInfo
- .asUpdatableMethodOptimizationInfo()
- .fixupClassTypeReferences(this, appView);
- } else {
- assert optimizationInfo.isDefaultMethodOptimizationInfo();
- }
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaTypeVisitor.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaTypeVisitor.java
deleted file mode 100644
index 9dce489..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaTypeVisitor.java
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda;
-
-import com.android.tools.r8.graph.DexAnnotation;
-import com.android.tools.r8.graph.DexAnnotationElement;
-import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexCallSite;
-import com.android.tools.r8.graph.DexEncodedAnnotation;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexMethodHandle;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
-import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
-import java.util.function.Consumer;
-import java.util.function.Predicate;
-
-// Encapsulates the logic of visiting all lambda classes.
-final class LambdaTypeVisitor {
- private final DexItemFactory factory;
- private final Predicate<DexType> isLambdaType;
- private final Consumer<DexType> onLambdaType;
-
- LambdaTypeVisitor(DexItemFactory factory,
- Predicate<DexType> isLambdaType, Consumer<DexType> onLambdaType) {
- this.factory = factory;
- this.isLambdaType = isLambdaType;
- this.onLambdaType = onLambdaType;
- }
-
- void accept(DexCallSite callSite) {
- accept(callSite.methodProto);
- accept(callSite.bootstrapMethod);
- for (DexValue value : callSite.bootstrapArgs) {
- accept(value);
- }
- }
-
- private void accept(DexValue value) {
- switch (value.getValueKind()) {
- case ARRAY:
- for (DexValue elementValue : value.asDexValueArray().getValues()) {
- accept(elementValue);
- }
- break;
- case FIELD:
- accept(value.asDexValueField().value, null);
- break;
- case METHOD:
- accept(value.asDexValueMethod().value, null);
- break;
- case METHOD_HANDLE:
- accept(value.asDexValueMethodHandle().value);
- break;
- case METHOD_TYPE:
- accept(value.asDexValueMethodType().value);
- break;
- case TYPE:
- accept(value.asDexValueType().value);
- break;
- default:
- // Intentionally empty.
- }
- }
-
- void accept(DexMethodHandle handle) {
- if (handle.isFieldHandle()) {
- accept(handle.asField(), null);
- } else {
- assert handle.isMethodHandle();
- accept(handle.asMethod(), null);
- }
- }
-
- void accept(DexField field, DexType holderToIgnore) {
- accept(field.type);
- if (holderToIgnore != field.holder) {
- accept(field.holder);
- }
- }
-
- void accept(DexMethod method, DexType holderToIgnore) {
- if (holderToIgnore != method.holder) {
- accept(method.holder);
- }
- accept(method.proto);
- }
-
- void accept(DexProto proto) {
- accept(proto.returnType);
- accept(proto.parameters);
- }
-
- void accept(DexTypeList types) {
- for (DexType type : types.values) {
- accept(type);
- }
- }
-
- void accept(DexAnnotationSet annotationSet) {
- for (DexAnnotation annotation : annotationSet.annotations) {
- accept(annotation);
- }
- }
-
- void accept(ParameterAnnotationsList parameterAnnotationsList) {
- parameterAnnotationsList.forEachAnnotation(this::accept);
- }
-
- private void accept(DexAnnotation annotation) {
- accept(annotation.annotation);
- }
-
- private void accept(DexEncodedAnnotation annotation) {
- accept(annotation.type);
- for (DexAnnotationElement element : annotation.elements) {
- accept(element);
- }
- }
-
- private void accept(DexAnnotationElement element) {
- accept(element.value);
- }
-
- void accept(DexType type) {
- if (type == null) {
- return;
- }
- if (type.isPrimitiveType() || type.isVoidType() || type.isPrimitiveArrayType()) {
- return;
- }
- if (type.isArrayType()) {
- accept(type.toArrayElementType(factory));
- return;
- }
- if (isLambdaType.test(type)) {
- onLambdaType.accept(type);
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/ClassInitializerSourceCode.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/ClassInitializerSourceCode.java
deleted file mode 100644
index 0eec9af..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/ClassInitializerSourceCode.java
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
-import com.android.tools.r8.ir.analysis.type.TypeElement;
-import com.android.tools.r8.ir.code.Invoke.Type;
-import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
-import com.google.common.collect.Lists;
-import java.util.List;
-
-final class ClassInitializerSourceCode extends SyntheticSourceCode {
- private final DexItemFactory factory;
- private final KotlinLambdaGroup group;
-
- ClassInitializerSourceCode(
- DexMethod method, DexItemFactory factory, KotlinLambdaGroup group, Position callerPosition) {
- super(null, method, callerPosition);
- assert method.proto.returnType == factory.voidType;
- assert method.proto.parameters == DexTypeList.empty();
- this.factory = factory;
- this.group = group;
- }
-
- @Override
- protected void prepareInstructions() {
- DexType groupClassType = group.getGroupClassType();
- DexMethod lambdaConstructorMethod = factory.createMethod(groupClassType,
- factory.createProto(factory.voidType, factory.intType), factory.constructorMethodName);
-
- int instance = nextRegister(ValueType.OBJECT);
- int lambdaId = nextRegister(ValueType.INT);
- List<ValueType> argTypes = Lists.newArrayList(ValueType.OBJECT, ValueType.INT);
- List<Integer> argRegisters = Lists.newArrayList(instance, lambdaId);
-
- group.forEachLambda(
- info -> {
- DexType lambda = info.clazz.type;
- if (group.isSingletonLambda(lambda)) {
- int id = group.lambdaId(lambda);
- add(builder -> builder.addNewInstance(instance, groupClassType));
- add(builder -> builder.addConst(TypeElement.getInt(), lambdaId, id));
- add(
- builder ->
- builder.addInvoke(
- Type.DIRECT,
- lambdaConstructorMethod,
- lambdaConstructorMethod.proto,
- argTypes,
- argRegisters,
- false /* isInterface*/));
- add(
- builder ->
- builder.addStaticPut(instance, group.getSingletonInstanceField(factory, id)));
- }
- });
-
- assert this.nextInstructionIndex() > 0 : "no single field initialized";
- add(IRBuilder::addReturn);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java
deleted file mode 100644
index 117ee3b..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.EnclosingMethodAttribute;
-import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.ir.code.Invoke.Type;
-import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroup;
-import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
-import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.ThrowingConsumer;
-import com.google.common.collect.Lists;
-import java.util.List;
-import java.util.function.IntFunction;
-
-// Represents a j-style lambda group created to combine several lambda classes
-// generated by kotlin compiler for kotlin lambda expressions passed to java receivers,
-// like:
-//
-// --- Java --------------------------------------------------------------
-// public static void acceptString(Supplier<String> s) {
-// // ...
-// }
-// -----------------------------------------------------------------------
-// acceptString({ "A" })
-// -----------------------------------------------------------------------
-//
-// Regular stateless j-style lambda class structure looks like below:
-// NOTE: stateless j-style lambdas do not always have INSTANCE field.
-//
-// -----------------------------------------------------------------------------------------------
-// signature <T:Ljava/lang/Object;>Ljava/lang/Object;
-// Ljava/util/function/Supplier<Ljava/lang/String;>;
-// final class lambdas/LambdasKt$foo$4 implements java/util/function/Supplier {
-//
-// public synthetic bridge get()Ljava/lang/Object;
-//
-// public final get()Ljava/lang/String;
-// @Lorg/jetbrains/annotations/NotNull;() // invisible
-//
-// <init>()V
-//
-// public final static Llambdas/LambdasKt$foo$4; INSTANCE
-//
-// static <clinit>()V
-//
-// OUTERCLASS lambdas/LambdasKt foo (Ljava/lang/String;I)Lkotlin/jvm/functions/Function0;
-// final static INNERCLASS lambdas/LambdasKt$foo$4 null null
-// }
-// -----------------------------------------------------------------------------------------------
-//
-// Regular stateful j-style lambda class structure looks like below:
-//
-// -----------------------------------------------------------------------------------------------
-// signature <T:Ljava/lang/Object;>
-// Ljava/lang/Object;Ljava/util/function/Supplier<Ljava/lang/String;>;
-// declaration: lambdas/LambdasKt$foo$5<T> implements java.util.function.Supplier<java.lang.String>
-// final class lambdas/LambdasKt$foo$5 implements java/util/function/Supplier {
-//
-// public synthetic bridge get()Ljava/lang/Object;
-//
-// public final get()Ljava/lang/String;
-// @Lorg/jetbrains/annotations/NotNull;() // invisible
-//
-// <init>(Ljava/lang/String;I)V
-//
-// final synthetic Ljava/lang/String; $m
-// final synthetic I $v
-//
-// OUTERCLASS lambdas/LambdasKt foo (Ljava/lang/String;I)Lkotlin/jvm/functions/Function0;
-// final static INNERCLASS lambdas/LambdasKt$foo$5 null null
-// }
-// -----------------------------------------------------------------------------------------------
-//
-// Key j-style lambda class details:
-// - extends java.lang.Object
-// - implements *any* functional interface (Kotlin does not seem to support scenarios when
-// lambda can implement multiple interfaces).
-// - lambda class is created as an anonymous inner class
-// - lambda class carries generic signature and kotlin metadata attribute
-// - class instance fields represent captured values and have an instance constructor
-// with matching parameters initializing them (see the second class above)
-// - stateless lambda *may* be implemented as a singleton with a static field storing the
-// only instance and initialized in static class constructor (see the first class above)
-// - main lambda method usually matches an exact lambda signature and may have
-// generic signature attribute and nullability parameter annotations
-// - optional bridge method created to satisfy interface implementation and
-// forwarding call to lambda main method
-//
-final class JStyleLambdaGroup extends KotlinLambdaGroup {
- private JStyleLambdaGroup(GroupId id) {
- super(id);
- }
-
- @Override
- protected ClassBuilder getBuilder(DexItemFactory factory, InternalOptions options) {
- return new ClassBuilder(factory, options, "java-style lambda group");
- }
-
- @Override
- public ThrowingConsumer<DexClass, LambdaStructureError> lambdaClassValidator(
- Kotlin kotlin, AppInfoWithClassHierarchy appInfo) {
- return new ClassValidator(kotlin, appInfo);
- }
-
- @Override
- protected String getGroupSuffix() {
- return "js$";
- }
-
- // Specialized group id.
- final static class GroupId extends KotlinLambdaGroupId {
- GroupId(
- AppView<AppInfoWithLiveness> appView,
- String capture,
- DexType iface,
- String pkg,
- String signature,
- DexEncodedMethod mainMethod,
- InnerClassAttribute inner,
- EnclosingMethodAttribute enclosing) {
- super(appView, capture, iface, pkg, signature, mainMethod, inner, enclosing);
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj instanceof GroupId && computeEquals((KotlinLambdaGroupId) obj);
- }
-
- @Override
- String getLambdaKindDescriptor() {
- return "Kotlin j-style lambda group";
- }
-
- @Override
- public LambdaGroup createGroup() {
- return new JStyleLambdaGroup(this);
- }
- }
-
- // Specialized class validator.
- private class ClassValidator extends KotlinLambdaClassValidator {
- ClassValidator(Kotlin kotlin, AppInfoWithClassHierarchy appInfo) {
- super(kotlin, JStyleLambdaGroup.this, appInfo);
- }
-
- @Override
- int getInstanceInitializerMaxSize(List<DexEncodedField> captures) {
- return captures.size() + 2;
- }
-
- @Override
- int validateInstanceInitializerEpilogue(
- com.android.tools.r8.code.Instruction[] instructions, int index)
- throws LambdaStructureError {
- if (!(instructions[index] instanceof com.android.tools.r8.code.InvokeDirect
- || instructions[index] instanceof com.android.tools.r8.code.InvokeDirectRange)
- || instructions[index].getMethod() != kotlin.factory.objectMembers.constructor) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- index++;
- if (!(instructions[index] instanceof ReturnVoid)) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- return index + 1;
- }
- }
-
- // Specialized class builder.
- private final class ClassBuilder extends KotlinLambdaGroupClassBuilder<JStyleLambdaGroup> {
- ClassBuilder(DexItemFactory factory, InternalOptions options, String origin) {
- super(JStyleLambdaGroup.this, factory, options, origin);
- }
-
- @Override
- protected DexType getSuperClassType() {
- return factory.objectType;
- }
-
- @Override
- SyntheticSourceCode createInstanceInitializerSourceCode(
- DexType groupClassType, DexMethod initializerMethod, Position callerPosition) {
- return new InstanceInitializerSourceCode(
- factory,
- groupClassType,
- group.getLambdaIdField(factory),
- id -> group.getCaptureField(factory, id),
- initializerMethod,
- callerPosition);
- }
- }
-
- // Specialized instance initializer code.
- private static final class InstanceInitializerSourceCode
- extends KotlinInstanceInitializerSourceCode {
- private final DexMethod objectInitializer;
-
- InstanceInitializerSourceCode(
- DexItemFactory factory,
- DexType lambdaGroupType,
- DexField idField,
- IntFunction<DexField> fieldGenerator,
- DexMethod method,
- Position callerPosition) {
- super(lambdaGroupType, idField, fieldGenerator, method, callerPosition);
- this.objectInitializer = factory.objectMembers.constructor;
- }
-
- @Override
- void prepareSuperConstructorCall(int receiverRegister) {
- add(
- builder ->
- builder.addInvoke(
- Type.DIRECT,
- objectInitializer,
- objectInitializer.proto,
- Lists.newArrayList(ValueType.OBJECT),
- Lists.newArrayList(receiverRegister),
- false /* isInterface */));
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroupIdFactory.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroupIdFactory.java
deleted file mode 100644
index df72677..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroupIdFactory.java
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClassAccessFlags;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroup.LambdaStructureError;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroupId;
-import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-
-public final class JStyleLambdaGroupIdFactory extends KotlinLambdaGroupIdFactory {
- private static final JStyleLambdaGroupIdFactory INSTANCE = new JStyleLambdaGroupIdFactory();
-
- private JStyleLambdaGroupIdFactory() {}
-
- public static JStyleLambdaGroupIdFactory getInstance() {
- return INSTANCE;
- }
-
- @Override
- public LambdaGroupId validateAndCreate(
- AppView<AppInfoWithLiveness> appView, Kotlin kotlin, DexClass lambda)
- throws LambdaStructureError {
- boolean accessRelaxed =
- appView.options().getProguardConfiguration().isAccessModificationAllowed();
-
- // Ignore ACC_SUPER.
- ClassAccessFlags copy = lambda.accessFlags.copy();
- copy.unsetSuper();
- checkAccessFlags("class access flags", copy, PUBLIC_LAMBDA_CLASS_FLAGS, LAMBDA_CLASS_FLAGS);
-
- // Class and interface.
- validateSuperclass(kotlin, lambda);
- DexType iface = validateInterfaces(kotlin, lambda);
-
- validateStaticFields(kotlin, lambda);
- String captureSignature = validateInstanceFields(lambda, accessRelaxed);
- validateDirectMethods(lambda);
- DexEncodedMethod mainMethod = validateVirtualMethods(lambda);
- String genericSignature = validateAnnotations(appView, kotlin, lambda);
- InnerClassAttribute innerClass = validateInnerClasses(lambda);
-
- return new JStyleLambdaGroup.GroupId(
- appView,
- captureSignature,
- iface,
- accessRelaxed ? "" : lambda.type.getPackageDescriptor(),
- genericSignature,
- mainMethod,
- innerClass,
- lambda.getEnclosingMethodAttribute());
- }
-
- @Override
- void validateSuperclass(Kotlin kotlin, DexClass lambda) throws LambdaStructureError {
- if (lambda.superType != kotlin.factory.objectType) {
- throw new LambdaStructureError("implements " + lambda.superType.toSourceString() +
- " instead of java.lang.Object");
- }
- }
-
- @Override
- DexType validateInterfaces(Kotlin kotlin, DexClass lambda) throws LambdaStructureError {
- if (lambda.interfaces.size() == 0) {
- throw new LambdaStructureError("does not implement any interfaces");
- }
- if (lambda.interfaces.size() > 1) {
- throw new LambdaStructureError(
- "implements more than one interface: " + lambda.interfaces.size());
- }
-
- // We don't validate that the interface is actually a functional interface,
- // since it may be desugared, or optimized in any other way which should not
- // affect lambda class merging.
- return lambda.interfaces.values[0];
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java
deleted file mode 100644
index cfae611..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import com.android.tools.r8.code.Const16;
-import com.android.tools.r8.code.Const4;
-import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.EnclosingMethodAttribute;
-import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.ir.analysis.type.TypeElement;
-import com.android.tools.r8.ir.code.Invoke.Type;
-import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroup;
-import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
-import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.ThrowingConsumer;
-import com.google.common.collect.Lists;
-import java.util.List;
-import java.util.function.IntFunction;
-
-// Represents a k-style lambda group created to combine several lambda classes
-// generated by kotlin compiler for regular kotlin lambda expressions, like:
-//
-// -----------------------------------------------------------------------
-// fun foo(m: String, v: Int): () -> String {
-// val lambda: (String, Int) -> String = { s, i -> s.substring(i) }
-// return { "$m: $v" }
-// }
-// -----------------------------------------------------------------------
-//
-// Regular stateless k-style lambda class structure looks like below:
-// NOTE: stateless k-style lambdas do not always have INSTANCE field.
-//
-// -----------------------------------------------------------------------------------------------
-// // signature Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function2<
-// Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;>;
-// final class lambdas/LambdasKt$foo$lambda1$1
-// extends kotlin/jvm/internal/Lambda
-// implements kotlin/jvm/functions/Function2 {
-//
-// public synthetic bridge invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-//
-// public final invoke(Ljava/lang/String;I)Ljava/lang/String;
-// @Lorg/jetbrains/annotations/NotNull;() // invisible
-// @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
-//
-// <init>()V
-//
-// public final static Llambdas/LambdasKt$foo$lambda1$1; INSTANCE
-//
-// static <clinit>()V
-//
-// OUTERCLASS lambdas/LambdasKt foo (Ljava/lang/String;I)Lkotlin/jvm/functions/Function0;
-// final static INNERCLASS lambdas/LambdasKt$foo$lambda1$1 null null
-// }
-// -----------------------------------------------------------------------------------------------
-//
-// Regular stateful k-style lambda class structure looks like below:
-//
-// -----------------------------------------------------------------------------------------------
-// // signature Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function0<Ljava/lang/String;>;
-// final class lambdas/LambdasKt$foo$1
-// extends kotlin/jvm/internal/Lambda
-// implements kotlin/jvm/functions/Function0 {
-//
-// public synthetic bridge invoke()Ljava/lang/Object;
-//
-// public final invoke()Ljava/lang/String;
-// @Lorg/jetbrains/annotations/NotNull;() // invisible
-//
-// <init>(Ljava/lang/String;I)V
-//
-// final synthetic Ljava/lang/String; $m
-// final synthetic I $v
-//
-// OUTERCLASS lambdas/LambdasKt foo (Ljava/lang/String;I)Lkotlin/jvm/functions/Function0;
-// final static INNERCLASS lambdas/LambdasKt$foo$1 null null
-// }
-// -----------------------------------------------------------------------------------------------
-//
-// Key k-style lambda class details:
-// - extends kotlin.jvm.internal.Lambda
-// - implements one of kotlin.jvm.functions.Function0..Function22, or FunctionN
-// see: https://github.com/JetBrains/kotlin/blob/master/libraries/
-// stdlib/jvm/runtime/kotlin/jvm/functions/Functions.kt
-// and: https://github.com/JetBrains/kotlin/blob/master/spec-docs/function-types.md
-// - lambda class is created as an anonymous inner class
-// - lambda class carries generic signature and kotlin metadata attribute
-// - class instance fields represent captured values and have an instance constructor
-// with matching parameters initializing them (see the second class above)
-// - stateless lambda *may* be implemented as a singleton with a static field storing the
-// only instance and initialized in static class constructor (see the first class above)
-// - main lambda method usually matches an exact lambda signature and may have
-// generic signature attribute and nullability parameter annotations
-// - optional bridge method created to satisfy interface implementation and
-// forwarding call to lambda main method
-//
-final class KStyleLambdaGroup extends KotlinLambdaGroup {
- private KStyleLambdaGroup(GroupId id) {
- super(id);
- }
-
- @Override
- protected ClassBuilder getBuilder(DexItemFactory factory, InternalOptions options) {
- return new ClassBuilder(factory, options, "kotlin-style lambda group");
- }
-
- @Override
- public ThrowingConsumer<DexClass, LambdaStructureError> lambdaClassValidator(
- Kotlin kotlin, AppInfoWithClassHierarchy appInfo) {
- return new ClassValidator(kotlin, appInfo);
- }
-
- @Override
- protected String getGroupSuffix() {
- return "ks$";
- }
-
- // Specialized group id.
- final static class GroupId extends KotlinLambdaGroupId {
- GroupId(
- AppView<AppInfoWithLiveness> appView,
- String capture,
- DexType iface,
- String pkg,
- String signature,
- DexEncodedMethod mainMethod,
- InnerClassAttribute inner,
- EnclosingMethodAttribute enclosing) {
- super(appView, capture, iface, pkg, signature, mainMethod, inner, enclosing);
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj instanceof GroupId && computeEquals((KotlinLambdaGroupId) obj);
- }
-
- @Override
- String getLambdaKindDescriptor() {
- return "Kotlin k-style lambda group";
- }
-
- @Override
- public LambdaGroup createGroup() {
- return new KStyleLambdaGroup(this);
- }
- }
-
- // Specialized class validator.
- private final class ClassValidator extends KotlinLambdaClassValidator {
- ClassValidator(Kotlin kotlin, AppInfoWithClassHierarchy appInfo) {
- super(kotlin, KStyleLambdaGroup.this, appInfo);
- }
-
- @Override
- int getInstanceInitializerMaxSize(List<DexEncodedField> captures) {
- return captures.size() + 3;
- }
-
- @Override
- int validateInstanceInitializerEpilogue(
- com.android.tools.r8.code.Instruction[] instructions, int index)
- throws LambdaStructureError {
- if (!(instructions[index] instanceof Const4) &&
- !(instructions[index] instanceof Const16)) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- index++;
- if (!(instructions[index] instanceof com.android.tools.r8.code.InvokeDirect
- || instructions[index] instanceof com.android.tools.r8.code.InvokeDirectRange)
- || instructions[index].getMethod() != kotlin.functional.lambdaInitializerMethod) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- index++;
- if (!(instructions[index] instanceof ReturnVoid)) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- return index + 1;
- }
- }
-
- // Specialized class builder.
- private final class ClassBuilder extends KotlinLambdaGroupClassBuilder<KStyleLambdaGroup> {
- ClassBuilder(DexItemFactory factory, InternalOptions options, String origin) {
- super(KStyleLambdaGroup.this, factory, options, origin);
- }
-
- @Override
- protected DexType getSuperClassType() {
- return factory.kotlin.functional.lambdaType;
- }
-
- @Override
- SyntheticSourceCode createInstanceInitializerSourceCode(
- DexType groupClassType, DexMethod initializerMethod, Position callerPosition) {
- return new InstanceInitializerSourceCode(
- factory,
- groupClassType,
- group.getLambdaIdField(factory),
- id -> group.getCaptureField(factory, id),
- initializerMethod,
- factory.kotlin.functional.getArity(id.iface),
- callerPosition);
- }
- }
-
- // Specialized instance initializer code.
- private final static class InstanceInitializerSourceCode
- extends KotlinInstanceInitializerSourceCode {
- private final int arity;
- private final DexMethod lambdaInitializer;
-
- InstanceInitializerSourceCode(
- DexItemFactory factory,
- DexType lambdaGroupType,
- DexField idField,
- IntFunction<DexField> fieldGenerator,
- DexMethod method,
- int arity,
- Position callerPosition) {
- super(lambdaGroupType, idField, fieldGenerator, method, callerPosition);
- this.arity = arity;
- this.lambdaInitializer = factory.createMethod(factory.kotlin.functional.lambdaType,
- factory.createProto(factory.voidType, factory.intType), factory.constructorMethodName);
- }
-
- @Override
- void prepareSuperConstructorCall(int receiverRegister) {
- int arityRegister = nextRegister(ValueType.INT);
- add(builder -> builder.addConst(TypeElement.getInt(), arityRegister, arity));
- add(
- builder ->
- builder.addInvoke(
- Type.DIRECT,
- lambdaInitializer,
- lambdaInitializer.proto,
- Lists.newArrayList(ValueType.OBJECT, ValueType.INT),
- Lists.newArrayList(receiverRegister, arityRegister),
- false /* isInterface */));
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroupIdFactory.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroupIdFactory.java
deleted file mode 100644
index cc212bf..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroupIdFactory.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClassAccessFlags;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroup.LambdaStructureError;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroupId;
-import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-
-public final class KStyleLambdaGroupIdFactory extends KotlinLambdaGroupIdFactory {
- private static final KStyleLambdaGroupIdFactory INSTANCE = new KStyleLambdaGroupIdFactory();
-
- private KStyleLambdaGroupIdFactory() {}
-
- public static KStyleLambdaGroupIdFactory getInstance() {
- return INSTANCE;
- }
-
- @Override
- public LambdaGroupId validateAndCreate(
- AppView<AppInfoWithLiveness> appView, Kotlin kotlin, DexClass lambda)
- throws LambdaStructureError {
- boolean accessRelaxed =
- appView.options().getProguardConfiguration().isAccessModificationAllowed();
-
- // Ignore ACC_SUPER.
- ClassAccessFlags copy = lambda.accessFlags.copy();
- copy.unsetSuper();
- checkAccessFlags("class access flags", copy, PUBLIC_LAMBDA_CLASS_FLAGS, LAMBDA_CLASS_FLAGS);
-
- // Class and interface.
- validateSuperclass(kotlin, lambda);
- DexType iface = validateInterfaces(kotlin, lambda);
-
- validateStaticFields(kotlin, lambda);
- String captureSignature = validateInstanceFields(lambda, accessRelaxed);
- validateDirectMethods(lambda);
- DexEncodedMethod mainMethod = validateVirtualMethods(lambda);
- String genericSignature = validateAnnotations(appView, kotlin, lambda);
- InnerClassAttribute innerClass = validateInnerClasses(lambda);
-
- return new KStyleLambdaGroup.GroupId(
- appView,
- captureSignature,
- iface,
- accessRelaxed ? "" : lambda.type.getPackageDescriptor(),
- genericSignature,
- mainMethod,
- innerClass,
- lambda.getEnclosingMethodAttribute());
- }
-
- @Override
- void validateSuperclass(Kotlin kotlin, DexClass lambda) throws LambdaStructureError {
- if (lambda.superType != kotlin.functional.lambdaType) {
- throw new LambdaStructureError("implements " + lambda.superType.toSourceString() +
- " instead of kotlin.jvm.internal.Lambda");
- }
- }
-
- @Override
- DexType validateInterfaces(Kotlin kotlin, DexClass lambda) throws LambdaStructureError {
- if (lambda.interfaces.size() == 0) {
- throw new LambdaStructureError("does not implement any interfaces");
- }
- if (lambda.interfaces.size() > 1) {
- throw new LambdaStructureError(
- "implements more than one interface: " + lambda.interfaces.size());
- }
- DexType iface = lambda.interfaces.values[0];
- if (!kotlin.functional.isFunctionInterface(iface)) {
- throw new LambdaStructureError("implements " + iface.toSourceString() +
- " instead of kotlin functional interface.");
- }
- return iface;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinInstanceInitializerSourceCode.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinInstanceInitializerSourceCode.java
deleted file mode 100644
index 687b081..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinInstanceInitializerSourceCode.java
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
-import java.util.function.IntFunction;
-
-abstract class KotlinInstanceInitializerSourceCode extends SyntheticSourceCode {
- private final DexField idField;
- private final IntFunction<DexField> fieldGenerator;
-
- KotlinInstanceInitializerSourceCode(
- DexType lambdaGroupType,
- DexField idField,
- IntFunction<DexField> fieldGenerator,
- DexMethod method,
- Position callerPosition) {
- super(lambdaGroupType, method, callerPosition);
- this.idField = idField;
- this.fieldGenerator = fieldGenerator;
- }
-
- @Override
- protected void prepareInstructions() {
- int receiverRegister = getReceiverRegister();
-
- // Initialize lambda id field.
- add(builder -> builder.addInstancePut(getParamRegister(0), receiverRegister, idField));
-
- // Initialize capture values.
- DexType[] values = proto.parameters.values;
- for (int i = 1; i < values.length; i++) {
- int index = i;
- add(builder -> builder.addInstancePut(
- getParamRegister(index), receiverRegister, fieldGenerator.apply(index - 1)));
- }
-
- // Call superclass constructor.
- prepareSuperConstructorCall(receiverRegister);
-
- add(IRBuilder::addReturn);
- }
-
- abstract void prepareSuperConstructorCall(int receiverRegister);
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaClassValidator.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaClassValidator.java
deleted file mode 100644
index a956f84..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaClassValidator.java
+++ /dev/null
@@ -1,267 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import com.android.tools.r8.code.Format22c;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.code.Iput;
-import com.android.tools.r8.code.IputBoolean;
-import com.android.tools.r8.code.IputByte;
-import com.android.tools.r8.code.IputChar;
-import com.android.tools.r8.code.IputObject;
-import com.android.tools.r8.code.IputShort;
-import com.android.tools.r8.code.IputWide;
-import com.android.tools.r8.code.ReturnVoid;
-import com.android.tools.r8.code.SputObject;
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.Inliner.Reason;
-import com.android.tools.r8.ir.optimize.inliner.NopWhyAreYouNotInliningReporter;
-import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
-import com.android.tools.r8.ir.optimize.lambda.CaptureSignature;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroup.LambdaStructureError;
-import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.utils.ThrowingConsumer;
-import java.util.List;
-
-// Encapsulates the logic of deep-checking of the lambda class assumptions.
-//
-// For k- and j-style lambdas we only check the code of class and instance
-// initializers to ensure that their code performs no unexpected actions:
-//
-// (a) Class initializer is only present for stateless lambdas and does
-// nothing expect instantiating the instance and storing it in
-// static instance field.
-//
-// (b) Instance initializers stores all captured values in proper capture
-// fields and calls the super constructor passing arity to it.
-abstract class KotlinLambdaClassValidator
- implements ThrowingConsumer<DexClass, LambdaStructureError> {
-
- static final String LAMBDA_INIT_CODE_VERIFICATION_FAILED =
- "instance initializer code verification failed";
- private static final String LAMBDA_CLINIT_CODE_VERIFICATION_FAILED =
- "static initializer code verification failed";
-
- final Kotlin kotlin;
- private final KotlinLambdaGroup group;
- private final AppInfoWithClassHierarchy appInfo;
-
- KotlinLambdaClassValidator(
- Kotlin kotlin, KotlinLambdaGroup group, AppInfoWithClassHierarchy appInfo) {
- this.kotlin = kotlin;
- this.group = group;
- this.appInfo = appInfo;
- }
-
- // Report a structure error.
- final LambdaStructureError structureError(String s) {
- return new LambdaStructureError(s, false);
- }
-
- @Override
- public void accept(DexClass lambda) throws LambdaStructureError {
- if (!CaptureSignature.getCaptureSignature(lambda.instanceFields()).equals(group.id().capture)) {
- throw structureError("capture signature was modified");
- }
-
- DexEncodedMethod classInitializer = null;
- DexEncodedMethod instanceInitializer = null;
- for (DexEncodedMethod method : lambda.directMethods()) {
- // We only check bodies of class and instance initializers since we don't expect to
- // see any static or private methods and all virtual methods will be translated into
- // same methods dispatching on lambda id to proper code.
- if (method.isClassInitializer()) {
- Code code = method.getCode();
- if (!(group.isStateless() && group.isSingletonLambda(lambda.type))) {
- throw structureError("static initializer on non-singleton lambda");
- }
- if (classInitializer != null || code == null || !code.isDexCode()) {
- throw structureError(LAMBDA_CLINIT_CODE_VERIFICATION_FAILED);
- }
- validateStatelessLambdaClassInitializer(lambda, code.asDexCode());
- classInitializer = method;
-
- } else if (method.isInstanceInitializer()) {
- Code code = method.getCode();
- if (instanceInitializer != null || code == null || !code.isDexCode()) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- validateInstanceInitializer(lambda, code.asDexCode());
- instanceInitializer = method;
- }
- }
-
- if (group.isStateless() && group.isSingletonLambda(lambda.type) && (classInitializer == null)) {
- throw structureError("missing static initializer on singleton lambda");
- }
-
- // This check is actually not required for lambda class merging, we only have to do
- // this because group class method composition piggybacks on inlining which has
- // assertions checking when we can inline force-inlined methods. So we double-check
- // these assertion never triggers.
- //
- // NOTE: the real type name for lambda group class is not generated yet, but we
- // can safely use a fake one here.
- DexType fakeLambdaGroupType = kotlin.factory.createType(
- "L" + group.getTypePackage() + "-$$LambdaGroup$XXXX;");
- WhyAreYouNotInliningReporter whyAreYouNotInliningReporter =
- NopWhyAreYouNotInliningReporter.getInstance();
- for (DexEncodedMethod method : lambda.virtualMethods()) {
- if (!method.isInliningCandidate(
- fakeLambdaGroupType, Reason.SIMPLE, appInfo, whyAreYouNotInliningReporter)) {
- throw structureError("method " + method.method.toSourceString() +
- " is not inline-able into lambda group class");
- }
- }
- }
-
- abstract int getInstanceInitializerMaxSize(List<DexEncodedField> captures);
-
- abstract int validateInstanceInitializerEpilogue(
- com.android.tools.r8.code.Instruction[] instructions, int index) throws LambdaStructureError;
-
- private void validateInstanceInitializer(DexClass lambda, Code code)
- throws LambdaStructureError {
- List<DexEncodedField> captures = lambda.instanceFields();
- com.android.tools.r8.code.Instruction[] instructions = code.asDexCode().instructions;
- int index = 0;
-
- if (instructions.length > getInstanceInitializerMaxSize(captures)) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
-
- // Capture field assignments: go through captured fields in assumed order
- // and ensure they are assigned values from appropriate parameters.
- index = validateInstanceInitializerParameterMapping(captures, instructions, index);
-
- // Check the constructor epilogue: a call to superclass constructor.
- index = validateInstanceInitializerEpilogue(instructions, index);
- assert index == instructions.length;
- }
-
- private int validateInstanceInitializerParameterMapping(
- List<DexEncodedField> captures, Instruction[] instructions, int index)
- throws LambdaStructureError {
- int dead = 0;
- int wideFieldsSeen = 0;
- for (DexEncodedField field : captures) {
- if (field.getOptimizationInfo().isDead()) {
- dead++;
- continue;
- }
- switch (field.field.type.toShorty()) {
- case 'Z':
- if (!(instructions[index] instanceof IputBoolean)
- || (instructions[index].getField() != field.field)
- || (((Format22c) instructions[index]).A != (index + 1 + dead + wideFieldsSeen))) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- break;
-
- case 'B':
- if (!(instructions[index] instanceof IputByte)
- || (instructions[index].getField() != field.field)
- || (((Format22c) instructions[index]).A != (index + 1 + dead + wideFieldsSeen))) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- break;
-
- case 'S':
- if (!(instructions[index] instanceof IputShort)
- || (instructions[index].getField() != field.field)
- || (((Format22c) instructions[index]).A != (index + 1 + dead + wideFieldsSeen))) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- break;
-
- case 'C':
- if (!(instructions[index] instanceof IputChar)
- || (instructions[index].getField() != field.field)
- || (((Format22c) instructions[index]).A != (index + 1 + dead + wideFieldsSeen))) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- break;
-
- case 'I':
- case 'F':
- if (!(instructions[index] instanceof Iput)
- || (instructions[index].getField() != field.field)
- || (((Format22c) instructions[index]).A != (index + 1 + dead + wideFieldsSeen))) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- break;
-
- case 'J':
- case 'D':
- if (!(instructions[index] instanceof IputWide)
- || (instructions[index].getField() != field.field)
- || (((Format22c) instructions[index]).A != (index + 1 + dead + wideFieldsSeen))) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- wideFieldsSeen++;
- break;
-
- case 'L':
- if (!(instructions[index] instanceof IputObject)
- || (instructions[index].getField() != field.field)
- || (((Format22c) instructions[index]).A != (index + 1 + dead + wideFieldsSeen))) {
- throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
- }
- break;
-
- default:
- throw new Unreachable();
- }
- index++;
- }
- return index;
- }
-
- private void validateStatelessLambdaClassInitializer(DexClass lambda, Code code)
- throws LambdaStructureError {
- assert group.isStateless() && group.isSingletonLambda(lambda.type);
- com.android.tools.r8.code.Instruction[] instructions = code.asDexCode().instructions;
- if (instructions.length != 4) {
- throw structureError(LAMBDA_CLINIT_CODE_VERIFICATION_FAILED);
- }
- if (!(instructions[0] instanceof com.android.tools.r8.code.NewInstance)
- || ((com.android.tools.r8.code.NewInstance) instructions[0]).getType() != lambda.type) {
- throw structureError(LAMBDA_CLINIT_CODE_VERIFICATION_FAILED);
- }
- if (!(instructions[1] instanceof com.android.tools.r8.code.InvokeDirect
- || instructions[1] instanceof com.android.tools.r8.code.InvokeDirectRange)
- || !isLambdaInitializerMethod(lambda, instructions[1].getMethod())) {
- throw structureError(LAMBDA_CLINIT_CODE_VERIFICATION_FAILED);
- }
- if (!(instructions[2] instanceof SputObject)
- || !isLambdaSingletonField(lambda, instructions[2].getField())) {
- throw structureError(LAMBDA_CLINIT_CODE_VERIFICATION_FAILED);
- }
- if (!(instructions[3] instanceof ReturnVoid)) {
- throw structureError(LAMBDA_CLINIT_CODE_VERIFICATION_FAILED);
- }
- }
-
- private boolean isLambdaSingletonField(DexClass lambda, DexField field) {
- return field.type == lambda.type
- && field.holder == lambda.type
- && field.name == kotlin.functional.kotlinStyleLambdaInstanceName;
- }
-
- private boolean isLambdaInitializerMethod(DexClass holder, DexMethod method) {
- return method.holder == holder.type
- && method.name == kotlin.factory.constructorMethodName
- && method.proto.parameters.isEmpty()
- && method.proto.returnType == kotlin.factory.voidType;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaConstants.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaConstants.java
deleted file mode 100644
index 9ac5ca7..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaConstants.java
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.graph.ClassAccessFlags;
-import com.android.tools.r8.graph.FieldAccessFlags;
-import com.android.tools.r8.graph.MethodAccessFlags;
-
-interface KotlinLambdaConstants {
- // Default lambda class flags.
- ClassAccessFlags LAMBDA_CLASS_FLAGS =
- ClassAccessFlags.fromDexAccessFlags(Constants.ACC_FINAL);
- // Access-relaxed lambda class flags.
- ClassAccessFlags PUBLIC_LAMBDA_CLASS_FLAGS =
- ClassAccessFlags.fromDexAccessFlags(Constants.ACC_PUBLIC + Constants.ACC_FINAL);
-
- // Default lambda class initializer flags.
- MethodAccessFlags CLASS_INITIALIZER_FLAGS =
- MethodAccessFlags.fromSharedAccessFlags(Constants.ACC_STATIC, true);
- // Default lambda class constructor flags.
- MethodAccessFlags CONSTRUCTOR_FLAGS =
- MethodAccessFlags.fromSharedAccessFlags(0, true);
- // Access-relaxed lambda class constructor flags.
- MethodAccessFlags CONSTRUCTOR_FLAGS_RELAXED =
- MethodAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC, true);
-
- // Default main lambda method flags.
- MethodAccessFlags MAIN_METHOD_FLAGS =
- MethodAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC + Constants.ACC_FINAL, false);
- // Default bridge lambda method flags.
- MethodAccessFlags BRIDGE_METHOD_FLAGS =
- MethodAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC + Constants.ACC_SYNTHETIC + Constants.ACC_BRIDGE, false);
- // Bridge lambda method flags after inliner.
- MethodAccessFlags BRIDGE_METHOD_FLAGS_FIXED =
- MethodAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC, false);
-
- // Default singleton instance folding field flags.
- FieldAccessFlags SINGLETON_FIELD_FLAGS =
- FieldAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC + Constants.ACC_STATIC + Constants.ACC_FINAL);
- // Default instance (lambda capture) field flags.
- FieldAccessFlags CAPTURE_FIELD_FLAGS =
- FieldAccessFlags.fromSharedAccessFlags(
- Constants.ACC_FINAL + Constants.ACC_SYNTHETIC);
- // access-relaxed instance (lambda capture) field flags.
- FieldAccessFlags CAPTURE_FIELD_FLAGS_RELAXED =
- FieldAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC + Constants.ACC_FINAL + Constants.ACC_SYNTHETIC);
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroup.java
deleted file mode 100644
index fc3f2bd..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroup.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.lambda.CaptureSignature;
-import com.android.tools.r8.ir.optimize.lambda.CodeProcessor.Strategy;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroup;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroupId;
-
-// Represents a lambda group created to combine several lambda classes generated
-// by kotlin compiler for either regular kotlin lambda expressions (k-style lambdas)
-// or lambda expressions created to implement java SAM interface.
-abstract class KotlinLambdaGroup extends LambdaGroup {
- private final Strategy strategy = new KotlinLambdaGroupCodeStrategy(this);
-
- KotlinLambdaGroup(LambdaGroupId id) {
- super(id);
- }
-
- final KotlinLambdaGroupId id() {
- return (KotlinLambdaGroupId) id;
- }
-
- final boolean isStateless() {
- return id().capture.isEmpty();
- }
-
- final boolean hasAnySingletons() {
- assert isStateless();
- return anyLambda(info -> this.isSingletonLambda(info.clazz.type));
- }
-
- final boolean isSingletonLambda(DexType lambda) {
- assert isStateless();
- return lambdaSingletonField(lambda) != null;
- }
-
- // Field referencing singleton instance for a lambda with specified id.
- final DexField getSingletonInstanceField(DexItemFactory factory, int id) {
- return factory.createField(this.getGroupClassType(),
- this.getGroupClassType(), factory.createString("INSTANCE$" + id));
- }
-
- @Override
- protected String getTypePackage() {
- String pkg = id().pkg;
- return pkg.isEmpty() ? "" : (pkg + "/");
- }
-
- final DexProto createConstructorProto(DexItemFactory factory) {
- String capture = id().capture;
- DexType[] newParameters = new DexType[capture.length() + 1];
- newParameters[0] = factory.intType; // Lambda id.
- for (int i = 0; i < capture.length(); i++) {
- newParameters[i + 1] = CaptureSignature.fieldType(factory, capture, i);
- }
- return factory.createProto(factory.voidType, newParameters);
- }
-
- final DexField getLambdaIdField(DexItemFactory factory) {
- return factory.createField(this.getGroupClassType(), factory.intType, "$id$");
- }
-
- final int mapFieldIntoCaptureIndex(DexType lambda, DexField field) {
- return CaptureSignature.mapFieldIntoCaptureIndex(
- id().capture, lambdaCaptureFields(lambda), field);
- }
-
- final DexField getCaptureField(DexItemFactory factory, int index) {
- assert index >= 0 && index < id().capture.length();
- return factory.createField(this.getGroupClassType(),
- CaptureSignature.fieldType(factory, id().capture, index), "$capture$" + index);
- }
-
- @Override
- public Strategy getCodeStrategy() {
- return strategy;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupClassBuilder.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupClassBuilder.java
deleted file mode 100644
index 977bdcf..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupClassBuilder.java
+++ /dev/null
@@ -1,354 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
-
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClassAccessFlags;
-import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
-import com.android.tools.r8.graph.DexValue.DexValueNull;
-import com.android.tools.r8.graph.EnclosingMethodAttribute;
-import com.android.tools.r8.graph.GenericSignature;
-import com.android.tools.r8.graph.GenericSignature.ClassSignature;
-import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
-import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
-import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
-import com.android.tools.r8.ir.code.IntSwitch;
-import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroupClassBuilder;
-import com.android.tools.r8.ir.synthetic.SynthesizedCode;
-import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
-import com.android.tools.r8.origin.SynthesizedOrigin;
-import com.android.tools.r8.utils.Box;
-import com.android.tools.r8.utils.IntBox;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.TriConsumer;
-import com.google.common.collect.Lists;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-// Builds components of kotlin lambda group class.
-abstract class KotlinLambdaGroupClassBuilder<T extends KotlinLambdaGroup>
- extends LambdaGroupClassBuilder<T> implements KotlinLambdaConstants {
-
- final KotlinLambdaGroupId id;
- final InternalOptions options;
-
- KotlinLambdaGroupClassBuilder(
- T group, DexItemFactory factory, InternalOptions options, String origin) {
- super(group, factory, origin);
- this.id = group.id();
- this.options = options;
- }
-
- abstract SyntheticSourceCode createInstanceInitializerSourceCode(
- DexType groupClassType, DexMethod initializerMethod, Position callerPosition);
-
- // Always generate public final classes.
- @Override
- protected ClassAccessFlags buildAccessFlags() {
- return PUBLIC_LAMBDA_CLASS_FLAGS;
- }
-
- // Take the attribute from the group, if exists.
- @Override
- protected EnclosingMethodAttribute buildEnclosingMethodAttribute() {
- return id.enclosing;
- }
-
- // Take the attribute from the group, if exists.
- @Override
- protected List<InnerClassAttribute> buildInnerClasses() {
- return !id.hasInnerClassAttribute()
- ? Collections.emptyList()
- : Lists.newArrayList(
- new InnerClassAttribute(id.innerClassAccess, group.getGroupClassType(), null, null));
- }
-
- @Override
- protected ClassSignature buildClassSignature() {
- // Kotlin-style lambdas supported by the merged may only contain optional signature and
- // kotlin metadata annotations. We remove the latter, but keep the signature if present.
- return GenericSignature.parseClassSignature(
- origin, id.signature, new SynthesizedOrigin(origin, getClass()), factory, options.reporter);
- }
-
- @Override
- protected DexEncodedMethod[] buildVirtualMethods() {
- // All virtual method are dispatched on $id$ field.
- //
- // For each of the virtual method name/signatures seen in the group
- // we generate a correspondent method in lambda group class with same
- // name/signatures dispatching the call to appropriate code taken
- // from the lambda class.
-
- Map<DexString, Map<DexProto, List<DexEncodedMethod>>> methods = collectVirtualMethods();
- List<DexEncodedMethod> result = new ArrayList<>();
-
- for (Entry<DexString, Map<DexProto, List<DexEncodedMethod>>> upper : methods.entrySet()) {
- DexString methodName = upper.getKey();
- for (Entry<DexProto, List<DexEncodedMethod>> inner : upper.getValue().entrySet()) {
- // Methods for unique name/signature pair.
- DexProto methodProto = inner.getKey();
- List<DexEncodedMethod> implMethods = inner.getValue();
-
- boolean isMainMethod =
- id.mainMethodName == methodName && id.mainMethodProto == methodProto;
-
- // Merging lambdas can introduce methods with too many instructions for the verifier on
- // ART to give up statically verifying the method. We therefore split up the implementation
- // methods and chain them with fallthrough:
- // function <method>() {
- // switch(field.id) {
- // case 1:
- // case 2:
- // ...
- // case n:
- // default: <method$1>()
- // }
- //
- // function <method$1>() {
- // case n + 1:
- // case n + 2:
- // ...
- // case n + m:
- // default: throw null
- // }
- IntBox counter = new IntBox(0);
- Box<DexMethod> currentMethodBox =
- new Box<>(factory.createMethod(group.getGroupClassType(), methodProto, methodName));
- splitIntoGroupsBasedOnInstructionSize(
- implMethods,
- (implMethodsToAdd, methodsSoFar, methodsRemaining) -> {
- assert currentMethodBox.isSet();
- // For bridge methods we still use same PUBLIC FINAL as for the main method,
- // since inlining removes BRIDGE & SYNTHETIC attributes from the bridge methods
- // anyways and our new method is a product of inlining.
- MethodAccessFlags accessFlags = MAIN_METHOD_FLAGS.copy();
- DexMethod method = currentMethodBox.get();
- DexMethod fallthrough =
- methodsRemaining
- ? factory.createMethod(
- group.getGroupClassType(),
- methodProto,
- methodName.toString() + "$" + counter.getAndIncrement())
- : null;
- result.add(
- new DexEncodedMethod(
- method,
- accessFlags,
- MethodTypeSignature.noSignature(),
- isMainMethod ? id.mainMethodAnnotations : DexAnnotationSet.empty(),
- isMainMethod
- ? id.mainMethodParamAnnotations
- : ParameterAnnotationsList.empty(),
- new SynthesizedCode(
- callerPosition ->
- new KotlinLambdaVirtualMethodSourceCode(
- factory,
- group.getGroupClassType(),
- method,
- group.getLambdaIdField(factory),
- implMethodsToAdd,
- fallthrough,
- methodsSoFar,
- callerPosition)),
- true));
- currentMethodBox.set(fallthrough);
- });
- assert !currentMethodBox.isSet();
- }
- }
- return result.toArray(DexEncodedMethod.EMPTY_ARRAY);
- }
-
- private void splitIntoGroupsBasedOnInstructionSize(
- List<DexEncodedMethod> implMethods,
- TriConsumer<List<DexEncodedMethod>, Integer, Boolean> consumer) {
- List<DexEncodedMethod> methods = new ArrayList<>();
- // Upper bound in DEX for reading the field for switching on the group id.
- final int fieldLoadInstructionSize = 10;
- int verificationSizeLimitInBytes = options.verificationSizeLimitInBytes();
- int currentInstructionsSize = fieldLoadInstructionSize;
- int implMethodsCommitted = 0;
- for (DexEncodedMethod implMethod : implMethods) {
- int packedSwitchPayloadSize =
- (int)
- (IntSwitch.basePackedSize(options.getInternalOutputMode())
- + IntSwitch.packedPayloadSize(options.getInternalOutputMode(), methods.size()));
- Code code = implMethod.getCode();
- // We only do lambda merging for DEX. If we started doing lambda merging for CF, we would
- // have to compute a size.
- assert code.isDexCode();
- int codeSize = code.asDexCode().codeSizeInBytes();
- int estimatedMethodSize = currentInstructionsSize + codeSize + packedSwitchPayloadSize;
- if (methods.size() > 0 && estimatedMethodSize > verificationSizeLimitInBytes) {
- consumer.accept(methods, implMethodsCommitted, true);
- currentInstructionsSize = fieldLoadInstructionSize;
- implMethodsCommitted += methods.size();
- methods = new ArrayList<>();
- }
- methods.add(implMethod);
- currentInstructionsSize += codeSize;
- }
- consumer.accept(methods, implMethodsCommitted, false);
- }
-
- // Build a map of virtual methods with unique name/proto pointing to a list of methods
- // from lambda classes implementing appropriate logic. The indices in the list correspond
- // to lambda ids. Note that some of the slots in the lists may be empty, indicating the
- // fact that corresponding lambda does not have a virtual method with this signature.
- private Map<DexString, Map<DexProto, List<DexEncodedMethod>>> collectVirtualMethods() {
- Map<DexString, Map<DexProto, List<DexEncodedMethod>>> methods = new LinkedHashMap<>();
- int size = group.size();
- group.forEachLambda(info -> {
- for (DexEncodedMethod method : info.clazz.virtualMethods()) {
- List<DexEncodedMethod> list = methods
- .computeIfAbsent(method.method.name,
- k -> new LinkedHashMap<>())
- .computeIfAbsent(method.method.proto,
- k -> Lists.newArrayList(Collections.nCopies(size, null)));
- assert list.get(info.id) == null;
- list.set(info.id, method);
- }
- });
- return methods;
- }
-
- @Override
- protected DexEncodedMethod[] buildDirectMethods() {
- // We only build an instance initializer and optional class
- // initializer for stateless lambdas.
-
- boolean needsSingletonInstances = group.isStateless() && group.hasAnySingletons();
- DexType groupClassType = group.getGroupClassType();
-
- DexEncodedMethod[] result = new DexEncodedMethod[needsSingletonInstances ? 2 : 1];
- // Instance initializer mapping parameters into capture fields.
- DexProto initializerProto = group.createConstructorProto(factory);
- DexMethod initializerMethod =
- factory.createMethod(groupClassType, initializerProto, factory.constructorMethodName);
- result[0] =
- new DexEncodedMethod(
- initializerMethod,
- CONSTRUCTOR_FLAGS_RELAXED, // always create access-relaxed constructor.
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- new SynthesizedCode(
- callerPosition ->
- createInstanceInitializerSourceCode(
- groupClassType, initializerMethod, callerPosition)),
- true);
-
- // Static class initializer for stateless lambdas.
- if (needsSingletonInstances) {
- DexMethod method =
- factory.createMethod(
- groupClassType,
- factory.createProto(factory.voidType),
- factory.classConstructorMethodName);
- result[1] =
- new DexEncodedMethod(
- method,
- CLASS_INITIALIZER_FLAGS,
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- new SynthesizedCode(
- callerPosition ->
- new ClassInitializerSourceCode(method, factory, group, callerPosition)),
- true);
- }
-
- return result;
- }
-
- @Override
- protected DexEncodedField[] buildInstanceFields() {
- // Lambda id field plus other fields defined by the capture signature.
- String capture = id.capture;
- int size = capture.length();
- DexEncodedField[] result = new DexEncodedField[1 + size];
-
- result[0] =
- new DexEncodedField(
- group.getLambdaIdField(factory),
- CAPTURE_FIELD_FLAGS_RELAXED,
- FieldTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- null);
-
- for (int id = 0; id < size; id++) {
- result[id + 1] =
- new DexEncodedField(
- group.getCaptureField(factory, id),
- CAPTURE_FIELD_FLAGS_RELAXED,
- FieldTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- null);
- }
-
- return result;
- }
-
- @Override
- protected DexEncodedField[] buildStaticFields(
- AppView<? extends AppInfoWithClassHierarchy> appView, OptimizationFeedback feedback) {
- if (!group.isStateless()) {
- return DexEncodedField.EMPTY_ARRAY;
- }
- // One field for each singleton lambda in the group.
- List<DexEncodedField> result = new ArrayList<>(group.size());
- group.forEachLambda(
- info -> {
- if (group.isSingletonLambda(info.clazz.type)) {
- DexField field = group.getSingletonInstanceField(factory, info.id);
- DexEncodedField encodedField =
- new DexEncodedField(
- field,
- SINGLETON_FIELD_FLAGS,
- FieldTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- DexValueNull.NULL);
- result.add(encodedField);
-
- // Record that the field is definitely not null. It is guaranteed to be assigned in the
- // class initializer of the enclosing class before it is read.
- ClassTypeElement exactType =
- ClassTypeElement.create(field.type, definitelyNotNull(), appView);
- feedback.markFieldHasDynamicLowerBoundType(encodedField, exactType);
- feedback.markFieldHasDynamicUpperBoundType(encodedField, exactType);
- }
- });
- assert result.isEmpty() == !group.hasAnySingletons();
- return result.toArray(DexEncodedField.EMPTY_ARRAY);
- }
-
- @Override
- protected DexTypeList buildInterfaces() {
- return new DexTypeList(new DexType[]{id.iface});
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
deleted file mode 100644
index 2c88700..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
+++ /dev/null
@@ -1,310 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
-import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
-
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.analysis.type.TypeElement;
-import com.android.tools.r8.ir.code.Argument;
-import com.android.tools.r8.ir.code.CheckCast;
-import com.android.tools.r8.ir.code.ConstNumber;
-import com.android.tools.r8.ir.code.InitClass;
-import com.android.tools.r8.ir.code.InstanceGet;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.InvokeDirect;
-import com.android.tools.r8.ir.code.InvokeMethod;
-import com.android.tools.r8.ir.code.InvokeVirtual;
-import com.android.tools.r8.ir.code.NewInstance;
-import com.android.tools.r8.ir.code.StaticGet;
-import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.optimize.lambda.CaptureSignature;
-import com.android.tools.r8.ir.optimize.lambda.CodeProcessor;
-import com.android.tools.r8.ir.optimize.lambda.CodeProcessor.Strategy;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroup;
-import com.android.tools.r8.ir.optimize.lambda.LambdaMerger.ApplyStrategy;
-import java.util.ArrayList;
-import java.util.List;
-
-// Defines the code processing strategy for kotlin lambdas.
-final class KotlinLambdaGroupCodeStrategy implements Strategy {
- private final KotlinLambdaGroup group;
-
- KotlinLambdaGroupCodeStrategy(KotlinLambdaGroup group) {
- this.group = group;
- }
-
- @Override
- public LambdaGroup group() {
- return group;
- }
-
- @Override
- public boolean isValidStaticFieldWrite(CodeProcessor context, DexField field) {
- DexType lambda = field.holder;
- assert group.containsLambda(lambda);
- // Only support writes to singleton static field named 'INSTANCE' from lambda
- // static class initializer.
- return field.name == context.kotlin.functional.kotlinStyleLambdaInstanceName
- && lambda == field.type
- && context.method.getDefinition().isClassInitializer()
- && context.method.getHolderType() == lambda;
- }
-
- @Override
- public boolean isValidStaticFieldRead(CodeProcessor context, DexField field) {
- DexType lambda = field.holder;
- assert group.containsLambda(lambda);
- // Support all reads of singleton static field named 'INSTANCE'.
- return field.name == context.kotlin.functional.kotlinStyleLambdaInstanceName
- && lambda == field.type;
- }
-
- @Override
- public boolean isValidInstanceFieldWrite(CodeProcessor context, DexField field) {
- DexType lambda = field.holder;
- DexMethod method = context.method.getReference();
- assert group.containsLambda(lambda);
- // Support writes to capture instance fields inside lambda constructor only.
- return method.holder == lambda && context.method.getDefinition().isInstanceInitializer();
- }
-
- @Override
- public boolean isValidInstanceFieldRead(CodeProcessor context, DexField field) {
- assert group.containsLambda(field.holder);
- // Support all reads from capture instance fields.
- return true;
- }
-
- @Override
- public boolean isValidNewInstance(CodeProcessor context, NewInstance invoke) {
- // Only valid for stateful lambdas.
- return !(group.isStateless() && group.isSingletonLambda(invoke.clazz));
- }
-
- @Override
- public boolean isValidInvoke(CodeProcessor context, InvokeMethod invoke) {
- return isValidInitializerCall(context, invoke) || isValidVirtualCall(invoke);
- }
-
- private boolean isValidInitializerCall(CodeProcessor context, InvokeMethod invoke) {
- DexMethod method = invoke.getInvokedMethod();
- DexType lambda = method.holder;
- assert group.containsLambda(lambda);
- // Allow calls to a constructor from other classes if the lambda is singleton,
- // otherwise allow such a call only from the same class static initializer.
- boolean isSingletonLambda = group.isStateless() && group.isSingletonLambda(lambda);
- return (isSingletonLambda == (context.method.getHolderType() == lambda))
- && invoke.isInvokeDirect()
- && context.factory.isConstructor(method)
- && CaptureSignature.getCaptureSignature(method.proto.parameters).equals(group.id().capture);
- }
-
- private boolean isValidVirtualCall(InvokeMethod invoke) {
- assert group.containsLambda(invoke.getInvokedMethod().holder);
- // Allow all virtual calls.
- return invoke.isInvokeVirtual();
- }
-
- @Override
- public boolean isValidInitClass(CodeProcessor context, DexType clazz) {
- assert group.containsLambda(clazz);
- // Support all init class instructions.
- return true;
- }
-
- @Override
- public boolean isValidHolder(CodeProcessor context, DexType holder) {
- assert group.containsLambda(holder);
- return true;
- }
-
- @Override
- public void patch(ApplyStrategy context, NewInstance newInstance) {
- DexType oldType = newInstance.clazz;
- DexType newType = group.getGroupClassType();
-
- NewInstance patchedNewInstance =
- new NewInstance(
- newType,
- context.code.createValue(
- TypeElement.fromDexType(newType, definitelyNotNull(), context.appView)));
- context.instructions().replaceCurrentInstruction(patchedNewInstance);
-
- assert newType != oldType;
- context.recordTypeHasChanged(patchedNewInstance.outValue());
- }
-
- @Override
- public void patch(ApplyStrategy context, InvokeMethod invoke) {
- assert group.containsLambda(invoke.getInvokedMethod().holder);
- if (isValidInitializerCall(context, invoke)) {
- patchInitializer(context, invoke.asInvokeDirect());
- } else {
- // Regular calls to virtual methods only need target method be replaced.
- assert isValidVirtualCall(invoke);
- DexMethod oldMethod = invoke.getInvokedMethod();
- DexMethod newMethod = mapVirtualMethod(context.factory, oldMethod);
-
- InvokeVirtual patchedInvokeVirtual =
- new InvokeVirtual(
- newMethod,
- createValueForType(context, newMethod.proto.returnType),
- invoke.arguments());
- context.instructions().replaceCurrentInstruction(patchedInvokeVirtual);
-
- // Otherwise, we need to record that the type of the out-value has changed.
- assert newMethod.proto.returnType == oldMethod.proto.returnType;
- }
- }
-
- @Override
- public void patch(ApplyStrategy context, InstanceGet instanceGet) {
- DexField oldField = instanceGet.getField();
- DexField newField = mapCaptureField(context.factory, oldField.holder, oldField);
-
- DexType oldFieldType = oldField.type;
- DexType newFieldType = newField.type;
-
- // We need to insert remapped values and in case the capture field
- // of type Object optionally cast to expected field.
- InstanceGet newInstanceGet =
- new InstanceGet(createValueForType(context, newFieldType), instanceGet.object(), newField);
- context.instructions().replaceCurrentInstruction(newInstanceGet);
-
- if (oldFieldType.isPrimitiveType() || oldFieldType == context.factory.objectType) {
- return;
- }
-
- // Since all captured values of non-primitive types are stored in fields of type
- // java.lang.Object, we need to cast them to appropriate type to satisfy the verifier.
- TypeElement castTypeLattice =
- TypeElement.fromDexType(oldFieldType, maybeNull(), context.appView);
- Value newValue = context.code.createValue(castTypeLattice, newInstanceGet.getLocalInfo());
- newInstanceGet.outValue().replaceUsers(newValue);
- CheckCast cast = new CheckCast(newValue, newInstanceGet.outValue(), oldFieldType);
- cast.setPosition(newInstanceGet.getPosition());
- context.instructions().add(cast);
-
- // If the current block has catch handlers split the check cast into its own block.
- // Since new cast is never supposed to fail, we leave catch handlers empty.
- if (cast.getBlock().hasCatchHandlers()) {
- context.instructions().previous();
- context.instructions().split(context.code, 1, context.blocks);
- }
- }
-
- @Override
- public void patch(ApplyStrategy context, StaticGet staticGet) {
- DexField oldField = staticGet.getField();
- DexField newField = mapSingletonInstanceField(context.factory, oldField);
-
- StaticGet patchedStaticGet =
- new StaticGet(
- context.code.createValue(
- TypeElement.fromDexType(newField.type, maybeNull(), context.appView)),
- newField);
- context.instructions().replaceCurrentInstruction(patchedStaticGet);
-
- assert newField.type != oldField.type;
- context.recordTypeHasChanged(patchedStaticGet.outValue());
- }
-
- @Override
- public void patch(ApplyStrategy context, InitClass initClass) {
- InitClass pachedInitClass =
- new InitClass(context.code.createValue(TypeElement.getInt()), group.getGroupClassType());
- context.instructions().replaceCurrentInstruction(pachedInitClass);
- }
-
- @Override
- public void patch(ApplyStrategy context, Argument argument) {
- // An argument can be a direct operand to a phi that we potentially could not remove.
- assert argument.getIndex() == 0;
- // The argument value will be replaced by the invoke value.
- argument
- .outValue()
- .setType(TypeElement.fromDexType(group.getGroupClassType(), maybeNull(), context.appView));
- context.recordTypeHasChanged(argument.outValue());
- }
-
- private void patchInitializer(CodeProcessor context, InvokeDirect invoke) {
- // Patching includes:
- // - change of methods
- // - adding lambda id as the first argument
- // - reshuffling other arguments (representing captured values)
- // according to capture signature of the group.
-
- DexMethod method = invoke.getInvokedMethod();
- DexType lambda = method.holder;
-
- // Create constant with lambda id.
- Value lambdaIdValue = context.code.createValue(TypeElement.getInt());
- ConstNumber lambdaId = new ConstNumber(lambdaIdValue, group.lambdaId(lambda));
- lambdaId.setPosition(invoke.getPosition());
- context.instructions().previous();
- context.instructions().add(lambdaId);
-
- // Create a new InvokeDirect instruction.
- Instruction next = context.instructions().next();
- assert next == invoke;
-
- DexMethod newTarget = mapInitializerMethod(context.factory, method);
- List<Value> newArguments = mapInitializerArgs(lambdaIdValue, invoke.arguments(), method.proto);
- context.instructions().replaceCurrentInstruction(
- new InvokeDirect(newTarget, null /* no return value */, newArguments)
- );
- }
-
- private Value createValueForType(CodeProcessor context, DexType returnType) {
- return returnType == context.factory.voidType
- ? null
- : context.code.createValue(
- TypeElement.fromDexType(returnType, maybeNull(), context.appView));
- }
-
- private List<Value> mapInitializerArgs(
- Value lambdaIdValue, List<Value> oldArguments, DexProto proto) {
- assert oldArguments.size() == proto.parameters.size() + 1;
- List<Value> newArguments = new ArrayList<>();
- newArguments.add(oldArguments.get(0)); // receiver
- newArguments.add(lambdaIdValue); // lambda-id
- List<Integer> reverseMapping =
- CaptureSignature.getReverseCaptureMapping(proto.parameters.values);
- for (int index : reverseMapping) {
- // <original-capture-index> = mapping[<normalized-capture-index>]
- newArguments.add(oldArguments.get(index + 1 /* after receiver */));
- }
- return newArguments;
- }
-
- // Map lambda class initializer into lambda group class initializer.
- private DexMethod mapInitializerMethod(DexItemFactory factory, DexMethod method) {
- assert factory.isConstructor(method);
- assert CaptureSignature.getCaptureSignature(method.proto.parameters).equals(group.id().capture);
- return factory.createMethod(group.getGroupClassType(),
- group.createConstructorProto(factory), method.name);
- }
-
- // Map lambda class virtual method into lambda group class method.
- private DexMethod mapVirtualMethod(DexItemFactory factory, DexMethod method) {
- return factory.createMethod(group.getGroupClassType(), method.proto, method.name);
- }
-
- // Map lambda class capture field into lambda group class capture field.
- private DexField mapCaptureField(DexItemFactory factory, DexType lambda, DexField field) {
- return group.getCaptureField(factory, group.mapFieldIntoCaptureIndex(lambda, field));
- }
-
- // Map lambda class initializer into lambda group class initializer.
- private DexField mapSingletonInstanceField(DexItemFactory factory, DexField field) {
- return group.getSingletonInstanceField(factory, group.lambdaId(field.holder));
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupId.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupId.java
deleted file mode 100644
index 7f24d79..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupId.java
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.EnclosingMethodAttribute;
-import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroup;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroupId;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-
-abstract class KotlinLambdaGroupId implements LambdaGroupId {
- private static final int MISSING_INNER_CLASS_ATTRIBUTE = -1;
-
- private final int hash;
-
- // Capture signature.
- final String capture;
- // Kotlin functional interface.
- final DexType iface;
- // Package (in case access relaxation is enabled root package is used).
- final String pkg;
- // Generic signature of the lambda class.
- final String signature;
-
- // Characteristics of the main lambda method. Kotlin generates one main method with
- // the signature matching the lambda signature, and a bridge method (if needed)
- // forwarding the call via interface to the main method. Main method may have
- // generic signature and parameter annotations defining nullability.
- //
- // TODO: address cases when main method is removed after inlining.
- // (the main method if created is supposed to be inlined, since it is always
- // only called from the bridge, and removed. In this case the method with
- // signature and annotations is removed allowing more lambda to be merged.)
- final DexString mainMethodName;
- final DexProto mainMethodProto;
- final DexAnnotationSet mainMethodAnnotations;
- final ParameterAnnotationsList mainMethodParamAnnotations;
-
- final EnclosingMethodAttribute enclosing;
-
- // Note that lambda classes are always created as _anonymous_ inner classes. We only
- // need to store the fact that the class had this attribute and if it had store the
- // access from InnerClassAttribute.
- final int innerClassAccess;
-
- KotlinLambdaGroupId(
- AppView<AppInfoWithLiveness> appView,
- String capture,
- DexType iface,
- String pkg,
- String signature,
- DexEncodedMethod mainMethod,
- InnerClassAttribute inner,
- EnclosingMethodAttribute enclosing) {
- assert capture != null && iface != null && pkg != null && mainMethod != null;
- assert inner == null || (inner.isAnonymous() && inner.getOuter() == null);
- this.capture = capture;
- this.iface = iface;
- this.pkg = pkg;
- this.signature = signature;
- this.mainMethodName = mainMethod.method.name;
- this.mainMethodProto = mainMethod.method.proto;
- this.mainMethodAnnotations = mainMethod.liveAnnotations(appView);
- this.mainMethodParamAnnotations = mainMethod.liveParameterAnnotations(appView);
- this.innerClassAccess = inner != null ? inner.getAccess() : MISSING_INNER_CLASS_ATTRIBUTE;
- this.enclosing = enclosing;
- this.hash = computeHashCode();
- }
-
- final boolean hasInnerClassAttribute() {
- return innerClassAccess != MISSING_INNER_CLASS_ATTRIBUTE;
- }
-
- @Override
- public final int hashCode() {
- return hash;
- }
-
- private int computeHashCode() {
- int hash = capture.hashCode() * 7;
- hash += iface.hashCode() * 17;
- hash += pkg.hashCode() * 37;
- hash += signature != null ? signature.hashCode() * 47 : 0;
- hash += mainMethodName.hashCode() * 71;
- hash += mainMethodProto.hashCode() * 89;
- hash += mainMethodAnnotations != null ? mainMethodAnnotations.hashCode() * 101 : 0;
- hash += mainMethodParamAnnotations != null ? mainMethodParamAnnotations.hashCode() * 113 : 0;
- hash += innerClassAccess * 131;
- hash += enclosing != null ? enclosing.hashCode() * 211 : 0;
- return hash;
- }
-
- @Override
- public abstract boolean equals(Object obj);
-
- boolean computeEquals(KotlinLambdaGroupId other) {
- return capture.equals(other.capture) &&
- iface == other.iface &&
- pkg.equals(other.pkg) &&
- mainMethodName == other.mainMethodName &&
- mainMethodProto == other.mainMethodProto &&
- (mainMethodAnnotations == null ? other.mainMethodAnnotations == null
- : mainMethodAnnotations.equals(other.mainMethodAnnotations)) &&
- (mainMethodParamAnnotations == null ? other.mainMethodParamAnnotations == null
- : mainMethodParamAnnotations.equals(other.mainMethodParamAnnotations)) &&
- (signature == null ? other.signature == null : signature.equals(other.signature)) &&
- innerClassAccess == other.innerClassAccess &&
- (enclosing == null ? other.enclosing == null : enclosing.equals(other.enclosing));
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder(getLambdaKindDescriptor())
- .append("\n capture: ").append(capture)
- .append("\n interface: ").append(iface.descriptor)
- .append("\n package: ").append(pkg)
- .append("\n signature: ").append(signature)
- .append("\n main method name: ").append(mainMethodName.toString())
- .append("\n main method: ").append(mainMethodProto.toSourceString())
- .append("\n main annotations: ").append(mainMethodAnnotations)
- .append("\n main param annotations: ").append(mainMethodParamAnnotations)
- .append("\n inner: ")
- .append(innerClassAccess == MISSING_INNER_CLASS_ATTRIBUTE ? "none" : innerClassAccess);
- if (enclosing != null) {
- if (enclosing.getEnclosingClass() != null) {
- builder.append("\n enclosingClass: ")
- .append(enclosing.getEnclosingClass().descriptor);
- } else {
- builder.append("\n enclosingMethod: ")
- .append(enclosing.getEnclosingMethod().toSourceString());
- }
- }
- return builder.toString();
- }
-
- abstract String getLambdaKindDescriptor();
-
- @Override
- public abstract LambdaGroup createGroup();
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupIdFactory.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupIdFactory.java
deleted file mode 100644
index 472d861..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupIdFactory.java
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import com.android.tools.r8.graph.AccessFlags;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexAnnotation;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.ir.optimize.lambda.CaptureSignature;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroup.LambdaStructureError;
-import com.android.tools.r8.ir.optimize.lambda.LambdaGroupId;
-import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import java.util.List;
-
-public abstract class KotlinLambdaGroupIdFactory implements KotlinLambdaConstants {
- KotlinLambdaGroupIdFactory() {
- }
-
- public static KotlinLambdaGroupIdFactory getFactoryForClass(DexProgramClass clazz) {
- if (clazz.getKotlinInfo().isSyntheticClass()
- && clazz.getKotlinInfo().asSyntheticClass().isLambda()) {
- if (clazz.getKotlinInfo().asSyntheticClass().isKotlinStyleLambda()) {
- return KStyleLambdaGroupIdFactory.getInstance();
- }
- assert clazz.getKotlinInfo().asSyntheticClass().isJavaStyleLambda();
- return JStyleLambdaGroupIdFactory.getInstance();
- }
- return null;
- }
-
- // Creates a lambda group id for a Java or Kotlin style lambda. Never returns null, but may throw
- // a LambdaStructureError if the lambda does not pass pre-requirements (mostly by not meeting
- // high-level structure expectations).
- //
- // At this point we only perform high-level checks before qualifying the lambda as a candidate
- // for merging and assigning lambda group id. We can NOT perform checks on method bodies since
- // they may not be converted yet, we'll do that in KStyleLambdaClassValidator.
- public abstract LambdaGroupId validateAndCreate(
- AppView<AppInfoWithLiveness> appView, Kotlin kotlin, DexClass lambda)
- throws LambdaStructureError;
-
- abstract void validateSuperclass(Kotlin kotlin, DexClass lambda) throws LambdaStructureError;
-
- abstract DexType validateInterfaces(Kotlin kotlin, DexClass lambda) throws LambdaStructureError;
-
- DexEncodedMethod validateVirtualMethods(DexClass lambda) throws LambdaStructureError {
- DexEncodedMethod mainMethod = null;
-
- for (DexEncodedMethod method : lambda.virtualMethods()) {
- if (method.accessFlags.materialize() == MAIN_METHOD_FLAGS.materialize()) {
- if (mainMethod != null) {
- throw new LambdaStructureError("more than one main method found");
- }
- mainMethod = method;
- } else {
- checkAccessFlags("unexpected virtual method access flags",
- method.accessFlags, BRIDGE_METHOD_FLAGS, BRIDGE_METHOD_FLAGS_FIXED);
- checkDirectMethodAnnotations(method);
- }
- }
-
- if (mainMethod == null) {
- // Missing main method may be a result of tree shaking.
- throw new LambdaStructureError("no main method found", false);
- }
- return mainMethod;
- }
-
- InnerClassAttribute validateInnerClasses(DexClass lambda) throws LambdaStructureError {
- List<InnerClassAttribute> innerClasses = lambda.getInnerClasses();
- if (innerClasses != null) {
- for (InnerClassAttribute inner : innerClasses) {
- if (inner.getInner() == lambda.type) {
- if (!inner.isAnonymous()) {
- throw new LambdaStructureError("is not anonymous");
- }
- return inner;
- }
- }
- }
- return null;
- }
-
- public static boolean hasValidAnnotations(Kotlin kotlin, DexClass lambda) {
- for (DexAnnotation annotation : lambda.annotations().annotations) {
- if (annotation.annotation.type == kotlin.factory.kotlinMetadataType) {
- continue;
- }
- return false;
- }
- return true;
- }
-
- String validateAnnotations(AppView<AppInfoWithLiveness> appView, Kotlin kotlin, DexClass lambda)
- throws LambdaStructureError {
- for (DexAnnotation annotation : lambda.liveAnnotations(appView).annotations) {
- if (annotation.annotation.type == appView.dexItemFactory().kotlinMetadataType) {
- // Ignore kotlin metadata on lambda classes. Metadata on synthetic
- // classes exists but is not used in the current Kotlin version (1.2.21)
- // and newly generated lambda _group_ class is not exactly a kotlin class.
- continue;
- }
-
- assert !hasValidAnnotations(kotlin, lambda);
- throw new LambdaStructureError(
- "unexpected annotation: " + annotation.annotation.type.toSourceString());
- }
- assert hasValidAnnotations(kotlin, lambda);
- return lambda.getClassSignature().toString();
- }
-
- void validateStaticFields(Kotlin kotlin, DexClass lambda) throws LambdaStructureError {
- List<DexEncodedField> staticFields = lambda.staticFields();
- if (staticFields.size() == 1) {
- DexEncodedField field = staticFields.get(0);
- if (field.field.name != kotlin.functional.kotlinStyleLambdaInstanceName ||
- field.field.type != lambda.type || !field.accessFlags.isPublic() ||
- !field.accessFlags.isFinal() || !field.accessFlags.isStatic()) {
- throw new LambdaStructureError("unexpected static field " + field.toSourceString());
- }
- // No state if the lambda is a singleton.
- if (lambda.instanceFields().size() > 0) {
- throw new LambdaStructureError("has instance fields along with INSTANCE");
- }
- checkAccessFlags("static field access flags", field.accessFlags, SINGLETON_FIELD_FLAGS);
- checkFieldAnnotations(field);
-
- } else if (staticFields.size() > 1) {
- throw new LambdaStructureError(
- "only one static field max expected, found " + staticFields.size());
- }
- }
-
- String validateInstanceFields(DexClass lambda, boolean accessRelaxed)
- throws LambdaStructureError {
- List<DexEncodedField> instanceFields = lambda.instanceFields();
- for (DexEncodedField field : instanceFields) {
- checkAccessFlags("capture field access flags", field.accessFlags,
- accessRelaxed ? CAPTURE_FIELD_FLAGS_RELAXED : CAPTURE_FIELD_FLAGS);
- checkFieldAnnotations(field);
- }
- return CaptureSignature.getCaptureSignature(instanceFields);
- }
-
- void validateDirectMethods(DexClass lambda) throws LambdaStructureError {
- for (DexEncodedMethod method : lambda.directMethods()) {
- if (method.isClassInitializer()) {
- // We expect to see class initializer only if there is a singleton field.
- if (lambda.staticFields().size() != 1) {
- throw new LambdaStructureError("has static initializer, but no singleton field");
- }
- checkAccessFlags(
- "unexpected static initializer access flags",
- method.accessFlags.getOriginalAccessFlags(),
- CLASS_INITIALIZER_FLAGS);
- checkDirectMethodAnnotations(method);
- } else if (method.isStatic()) {
- throw new LambdaStructureError(
- "unexpected static method: " + method.method.toSourceString());
- } else if (method.isInstanceInitializer()) {
- // Lambda class is expected to have one constructor
- // with parameters matching capture signature.
- DexType[] parameters = method.method.proto.parameters.values;
- List<DexEncodedField> instanceFields = lambda.instanceFields();
- if (parameters.length != instanceFields.size()) {
- throw new LambdaStructureError("constructor parameters don't match captured values.");
- }
- for (int i = 0; i < parameters.length; i++) {
- // Kotlin compiler sometimes reshuffles the parameters so that their order
- // in the constructor don't match order of capture fields. We could add
- // support for it, but it happens quite rarely so don't bother for now.
- if (parameters[i] != instanceFields.get(i).field.type) {
- throw new LambdaStructureError(
- "constructor parameters don't match captured values.", false);
- }
- }
- checkAccessFlags("unexpected constructor access flags",
- method.accessFlags, CONSTRUCTOR_FLAGS, CONSTRUCTOR_FLAGS_RELAXED);
- checkDirectMethodAnnotations(method);
-
- } else if (method.isPrivateMethod()) {
- // TODO(b/135975229)
- throw new LambdaStructureError("private method: " + method.method.toSourceString());
- } else {
- assert false;
- throw new LambdaStructureError(
- "unexpected method encountered: " + method.method.toSourceString());
- }
- }
- }
-
- private static void checkDirectMethodAnnotations(DexEncodedMethod method)
- throws LambdaStructureError {
- if (!method.annotations().isEmpty()) {
- throw new LambdaStructureError(
- "unexpected method annotations ["
- + method.annotations().toSmaliString()
- + "] on "
- + method.method.toSourceString());
- }
- if (!method.parameterAnnotationsList.isEmpty()) {
- throw new LambdaStructureError(
- "unexpected method parameters annotations ["
- + method.parameterAnnotationsList.toSmaliString()
- + "] on "
- + method.method.toSourceString());
- }
- }
-
- private static void checkFieldAnnotations(DexEncodedField field) throws LambdaStructureError {
- if (field.hasAnnotation()) {
- throw new LambdaStructureError(
- "unexpected field annotations ["
- + field.annotations().toSmaliString()
- + "] on "
- + field.field.toSourceString());
- }
- }
-
- @SafeVarargs
- static <T extends AccessFlags> void checkAccessFlags(
- String message, T actual, T... expected) throws LambdaStructureError {
- checkAccessFlags(message, actual.materialize(), expected);
- }
-
- @SafeVarargs
- private static <T extends AccessFlags> void checkAccessFlags(
- String message, int actual, T... expected) throws LambdaStructureError {
- for (T flag : expected) {
- if (actual == flag.materialize()) {
- return;
- }
- }
- throw new LambdaStructureError(message);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaVirtualMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaVirtualMethodSourceCode.java
deleted file mode 100644
index 657a796..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaVirtualMethodSourceCode.java
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright (c) 2018, 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.ir.optimize.lambda.kotlin;
-
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.code.Invoke;
-import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
-import java.util.ArrayList;
-import java.util.List;
-
-final class KotlinLambdaVirtualMethodSourceCode extends SyntheticSourceCode {
- private final DexItemFactory factory;
- private final DexField idField;
- private final List<DexEncodedMethod> implMethods;
- private final DexMethod fallThroughMethod;
- private final int keyStart;
-
- KotlinLambdaVirtualMethodSourceCode(
- DexItemFactory factory,
- DexType groupClass,
- DexMethod method,
- DexField idField,
- List<DexEncodedMethod> implMethods,
- DexMethod fallThroughMethod,
- int keyStart,
- Position callerPosition) {
- super(groupClass, method, callerPosition);
- this.factory = factory;
- this.idField = idField;
- this.implMethods = implMethods;
- this.fallThroughMethod = fallThroughMethod;
- this.keyStart = keyStart;
- }
-
- @Override
- protected void prepareInstructions() {
- int implMethodCount = implMethods.size();
- // We generate a single switch on lambda $id value read from appropriate
- // field, and for each lambda id generate a call to appropriate method of
- // the lambda class. Since this methods are marked as 'force inline',
- // they are inlined by the inliner.
-
- // Return value register if needed.
- DexType returnType = proto.returnType;
- boolean returnsValue = returnType != factory.voidType;
- ValueType retValueType = returnsValue ? ValueType.fromDexType(returnType) : null;
- int retRegister = returnsValue ? nextRegister(retValueType) : -1;
-
- // Lambda id register to switch on.
- int idRegister = nextRegister(ValueType.INT);
- add(builder -> builder.addInstanceGet(idRegister, getReceiverRegister(), idField));
-
- // Switch on id.
- // Note that 'keys' and 'offsets' are just captured here and filled
- // in with values when appropriate basic blocks are created.
- int[] keys = new int[implMethodCount];
- int[] offsets = new int[implMethodCount];
- int[] fallthrough = new int[1]; // Array as a container for late initialization.
- int switchIndex = lastInstructionIndex();
- add(builder -> builder.addSwitch(idRegister, keys, fallthrough[0], offsets),
- builder -> endsSwitch(builder, switchIndex, fallthrough[0], offsets));
-
- List<Value> arguments = new ArrayList<>(proto.parameters.values.length + 1);
-
- fallthrough[0] = nextInstructionIndex();
- if (fallThroughMethod == null) {
- // Fallthrough treated as unreachable.
- int nullRegister = nextRegister(ValueType.OBJECT);
- add(builder -> builder.addNullConst(nullRegister));
- add(builder -> builder.addThrow(nullRegister), endsBlock);
- } else {
- addMethodCall(fallThroughMethod, arguments, returnsValue, retRegister);
- }
-
- // Blocks for each lambda id.
- for (int i = 0; i < implMethodCount; i++) {
- keys[i] = keyStart + i;
- DexEncodedMethod impl = implMethods.get(i);
- if (impl == null) {
- // Virtual method is missing in lambda class.
- offsets[i] = fallthrough[0];
- continue;
- }
- offsets[i] = nextInstructionIndex();
- addMethodCall(impl.method, arguments, returnsValue, retRegister);
- }
- }
-
- private void addMethodCall(
- DexMethod method, List<Value> arguments, boolean returnsValue, int retRegister) {
- // Emit fake call on `this` receiver.
- add(
- builder -> {
- if (arguments.isEmpty()) {
- arguments.add(builder.getReceiverValue());
- List<Value> argumentValues = builder.getArgumentValues();
- if (argumentValues != null) {
- arguments.addAll(builder.getArgumentValues());
- }
- }
- builder.addInvoke(
- Invoke.Type.VIRTUAL, method, method.proto, arguments, false /* isInterface */);
- });
- // Handle return value if needed.
- if (returnsValue) {
- add(builder -> builder.addMoveResult(retRegister));
- add(builder -> builder.addReturn(retRegister), endsBlock);
- } else {
- add(IRBuilder::addReturn, endsBlock);
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
index 6b011a6..6fc09f5 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.kotlin.KotlinMetadataUtils.NO_KOTLIN_INFO;
import static com.android.tools.r8.kotlin.KotlinSyntheticClassInfo.getFlavour;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationElement;
import com.android.tools.r8.graph.DexClass;
@@ -35,11 +36,10 @@
DexClass clazz,
DexItemFactory factory,
Reporter reporter,
- boolean onlyProcessLambda,
Consumer<DexEncodedMethod> keepByteCode) {
DexAnnotation meta = clazz.annotations().getFirstMatching(factory.kotlinMetadataType);
if (meta != null) {
- return getKotlinInfo(kotlin, clazz, factory, reporter, onlyProcessLambda, keepByteCode, meta);
+ return getKotlinInfo(kotlin, clazz, factory, reporter, keepByteCode, meta);
}
return NO_KOTLIN_INFO;
}
@@ -49,14 +49,10 @@
DexClass clazz,
DexItemFactory factory,
Reporter reporter,
- boolean onlyProcessLambda,
Consumer<DexEncodedMethod> keepByteCode,
DexAnnotation annotation) {
try {
KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, annotation.annotation);
- if (onlyProcessLambda && !isSyntheticClassifiedLambda(kotlin, clazz, kMetadata)) {
- return NO_KOTLIN_INFO;
- }
return createKotlinInfo(kotlin, clazz, kMetadata, factory, reporter, keepByteCode);
} catch (ClassCastException | InconsistentKotlinMetadataException | MetadataError e) {
reporter.info(
@@ -77,12 +73,18 @@
}
}
- private static boolean isSyntheticClassifiedLambda(
- Kotlin kotlin, DexClass clazz, KotlinClassMetadata kMetadata) {
- if (kMetadata instanceof SyntheticClass) {
- SyntheticClass syntheticClass = (SyntheticClass) kMetadata;
- return syntheticClass.isLambda()
- && getFlavour(syntheticClass, clazz, kotlin) != Flavour.Unclassified;
+ public static boolean isLambda(AppView<?> appView, DexClass clazz) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ Kotlin kotlin = dexItemFactory.kotlin;
+ DexAnnotation metadataAnnotation =
+ clazz.annotations().getFirstMatching(dexItemFactory.kotlinMetadataType);
+ if (metadataAnnotation != null) {
+ KotlinClassMetadata kMetadata = toKotlinClassMetadata(kotlin, metadataAnnotation.annotation);
+ if (kMetadata instanceof SyntheticClass) {
+ SyntheticClass syntheticClass = (SyntheticClass) kMetadata;
+ return syntheticClass.isLambda()
+ && getFlavour(syntheticClass, clazz, kotlin) != Flavour.Unclassified;
+ }
}
return false;
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
index f9d2d18..4eef6cb 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataEnqueuerExtension.java
@@ -18,6 +18,8 @@
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.analysis.EnqueuerAnalysis;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.Enqueuer.EnqueuerDefinitionSupplier;
import com.google.common.collect.Sets;
@@ -25,6 +27,8 @@
public class KotlinMetadataEnqueuerExtension extends EnqueuerAnalysis {
+ private static final OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance();
+
private final AppView<?> appView;
private final EnqueuerDefinitionSupplier enqueuerDefinitionSupplier;
private final Set<DexType> prunedTypes;
@@ -57,23 +61,27 @@
Set<DexProgramClass> localOrAnonymousClasses = Sets.newIdentityHashSet();
enqueuer.forAllLiveClasses(
clazz -> {
- boolean onlyProcessLambdas = !keepMetadata || !enqueuer.isPinned(clazz.type);
assert clazz.getKotlinInfo().isNoKotlinInformation();
- clazz.setKotlinInfo(
- KotlinClassMetadataReader.getKotlinInfo(
- appView.dexItemFactory().kotlin,
- clazz,
- appView.dexItemFactory(),
- appView.options().reporter,
- onlyProcessLambdas,
- method -> keepByteCodeFunctions.add(method.method)));
- if (onlyProcessLambdas) {
+ if (!keepMetadata || !enqueuer.isPinned(clazz.getType())) {
+ if (KotlinClassMetadataReader.isLambda(appView, clazz)
+ && clazz.hasClassInitializer()) {
+ feedback.classInitializerMayBePostponed(clazz.getClassInitializer());
+ }
+ clazz.setKotlinInfo(NO_KOTLIN_INFO);
clazz.removeAnnotations(
annotation -> annotation.getAnnotationType() == kotlinMetadataType);
- }
- if (clazz.getEnclosingMethodAttribute() != null
- && clazz.getEnclosingMethodAttribute().getEnclosingMethod() != null) {
- localOrAnonymousClasses.add(clazz);
+ } else {
+ clazz.setKotlinInfo(
+ KotlinClassMetadataReader.getKotlinInfo(
+ appView.dexItemFactory().kotlin,
+ clazz,
+ appView.dexItemFactory(),
+ appView.options().reporter,
+ method -> keepByteCodeFunctions.add(method.getReference())));
+ if (clazz.getEnclosingMethodAttribute() != null
+ && clazz.getEnclosingMethodAttribute().getEnclosingMethod() != null) {
+ localOrAnonymousClasses.add(clazz);
+ }
}
});
appView.setCfByteCodePassThrough(keepByteCodeFunctions);
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
index 1001ca9..44d6ede 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -139,7 +139,7 @@
}
final KotlinClassLevelInfo kotlinInfo =
KotlinClassMetadataReader.getKotlinInfo(
- kotlin, clazz, factory, reporter, false, ConsumerUtils.emptyConsumer(), metadata);
+ kotlin, clazz, factory, reporter, ConsumerUtils.emptyConsumer(), metadata);
if (kotlinInfo == NO_KOTLIN_INFO) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 0d4a768..240d3b9 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -40,7 +40,6 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.horizontalclassmerging.HorizontallyMergedClasses;
import com.android.tools.r8.inspector.internal.InspectorImpl;
@@ -50,7 +49,6 @@
import com.android.tools.r8.ir.desugar.nest.Nest;
import com.android.tools.r8.ir.optimize.Inliner;
import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
-import com.android.tools.r8.ir.optimize.lambda.kotlin.KotlinLambdaGroupIdFactory;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
import com.android.tools.r8.references.Reference;
@@ -201,7 +199,6 @@
enableClassInlining = false;
enableClassStaticizer = false;
enableDevirtualization = false;
- enableLambdaMerging = false;
horizontalClassMergerOptions.disable();
enableVerticalClassMerging = false;
enableEnumUnboxing = false;
@@ -502,8 +499,6 @@
// Flag to turn on/offLoad/store optimization in the Cf back-end.
public boolean enableLoadStoreOptimization = true;
- // Flag to turn on/off lambda class merging in R8.
- public boolean enableLambdaMerging = false;
// Flag to turn on/off desugaring in D8/R8.
public DesugarState desugarState = DesugarState.ON;
// Flag to turn on/off reduction of nest to improve class merging optimizations.
@@ -1139,20 +1134,17 @@
public boolean enableConstructorMerging = true;
// TODO(b/174809311): Update or remove the option and its tests after new lambdas synthetics.
public boolean enableJavaLambdaMerging = false;
- public boolean enableKotlinLambdaMerging = true;
public int syntheticArgumentCount = 3;
public int maxGroupSize = 30;
+ // TODO(b/179019716): Add support for merging in presence of annotations.
+ public boolean skipNoClassesOrMembersWithAnnotationsPolicyForTesting = false;
+
public void disable() {
enable = false;
}
- @Deprecated
- public void disableKotlinLambdaMerging() {
- enableKotlinLambdaMerging = false;
- }
-
public void enable() {
enable = true;
}
@@ -1165,10 +1157,6 @@
enableJavaLambdaMerging = true;
}
- public void enableKotlinLambdaMergingIf(boolean enableKotlinLambdaMerging) {
- this.enableKotlinLambdaMerging = enableKotlinLambdaMerging;
- }
-
public int getMaxGroupSize() {
return maxGroupSize;
}
@@ -1192,10 +1180,6 @@
public boolean isJavaLambdaMergingEnabled() {
return enableJavaLambdaMerging;
}
-
- public boolean isKotlinLambdaMergingEnabled() {
- return enableKotlinLambdaMerging;
- }
}
public static class ProtoShrinkingOptions {
@@ -1243,9 +1227,6 @@
public BiConsumer<AppInfoWithLiveness, Enqueuer.Mode> enqueuerInspector = null;
- public Function<DexProgramClass, KotlinLambdaGroupIdFactory> kotlinLambdaMergerFactoryForClass =
- KotlinLambdaGroupIdFactory::getFactoryForClass;
-
public BiConsumer<ProgramMethod, MethodProcessingId> methodProcessingIdConsumer = null;
public Function<AppView<AppInfoWithLiveness>, RepackagingConfiguration>
@@ -1257,9 +1238,6 @@
public BiConsumer<DexItemFactory, HorizontallyMergedClasses> horizontallyMergedClassesConsumer =
ConsumerUtils.emptyBiConsumer();
- public BiConsumer<DexItemFactory, HorizontallyMergedLambdaClasses>
- horizontallyMergedLambdaClassesConsumer = ConsumerUtils.emptyBiConsumer();
-
public BiConsumer<DexItemFactory, EnumDataMap> unboxedEnumsConsumer =
ConsumerUtils.emptyBiConsumer();
diff --git a/src/test/java/com/android/tools/r8/KotlinTestBase.java b/src/test/java/com/android/tools/r8/KotlinTestBase.java
index f8dc222..38202a6 100644
--- a/src/test/java/com/android/tools/r8/KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/KotlinTestBase.java
@@ -41,10 +41,12 @@
protected final KotlinCompiler kotlinc;
protected final KotlinTargetVersion targetVersion;
+ protected final KotlinTestParameters kotlinParameters;
- protected KotlinTestBase(KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- this.targetVersion = targetVersion;
- this.kotlinc = kotlinc;
+ protected KotlinTestBase(KotlinTestParameters kotlinParameters) {
+ this.targetVersion = kotlinParameters.getTargetVersion();
+ this.kotlinc = kotlinParameters.getCompiler();
+ this.kotlinParameters = kotlinParameters;
}
protected static List<Path> getKotlinFilesInTestPackage(Package pkg) throws IOException {
@@ -125,6 +127,11 @@
return this;
}
+ public Path getForConfiguration(KotlinTestParameters kotlinParameters) {
+ return getForConfiguration(
+ kotlinParameters.getCompiler(), kotlinParameters.getTargetVersion());
+ }
+
public Path getForConfiguration(KotlinCompiler compiler, KotlinTargetVersion targetVersion) {
Map<KotlinTargetVersion, Path> kotlinTargetVersionPathMap = compiledPaths.get(compiler);
if (kotlinTargetVersionPathMap == null) {
diff --git a/src/test/java/com/android/tools/r8/KotlinTestParameters.java b/src/test/java/com/android/tools/r8/KotlinTestParameters.java
new file mode 100644
index 0000000..69a1cff
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/KotlinTestParameters.java
@@ -0,0 +1,95 @@
+// Copyright (c) 2019, 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;
+
+import static org.junit.Assert.assertNotNull;
+
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import java.util.ArrayList;
+import java.util.List;
+
+public class KotlinTestParameters {
+
+ private final int index;
+ private final KotlinCompiler kotlinc;
+ private final KotlinTargetVersion targetVersion;
+
+ private KotlinTestParameters(
+ KotlinCompiler kotlinc, KotlinTargetVersion targetVersion, int index) {
+ this.index = index;
+ this.kotlinc = kotlinc;
+ this.targetVersion = targetVersion;
+ }
+
+ public KotlinCompiler getCompiler() {
+ return kotlinc;
+ }
+
+ public KotlinTargetVersion getTargetVersion() {
+ return targetVersion;
+ }
+
+ public boolean isFirst() {
+ return index == 0;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public String toString() {
+ return kotlinc + "[target=" + targetVersion + "]";
+ }
+
+ public static class Builder {
+
+ private KotlinCompiler[] compilers;
+ private KotlinTargetVersion[] targetVersions;
+
+ private Builder() {}
+
+ public Builder withAllCompilers() {
+ compilers = ToolHelper.getKotlinCompilers();
+ return this;
+ }
+
+ public Builder withAllCompilersAndTargetVersions() {
+ return withAllCompilers().withAllTargetVersions();
+ }
+
+ public Builder withCompiler(KotlinCompiler compiler) {
+ compilers = new KotlinCompiler[] {compiler};
+ return this;
+ }
+
+ public Builder withAllTargetVersions() {
+ targetVersions = KotlinTargetVersion.values();
+ return this;
+ }
+
+ public Builder withTargetVersion(KotlinTargetVersion targetVersion) {
+ targetVersions = new KotlinTargetVersion[] {targetVersion};
+ return this;
+ }
+
+ public KotlinTestParametersCollection build() {
+ validate();
+ List<KotlinTestParameters> testParameters = new ArrayList<>();
+ int index = 0;
+ for (KotlinCompiler kotlinc : compilers) {
+ for (KotlinTargetVersion targetVersion : targetVersions) {
+ testParameters.add(new KotlinTestParameters(kotlinc, targetVersion, index++));
+ }
+ }
+ return new KotlinTestParametersCollection(testParameters);
+ }
+
+ private void validate() {
+ assertNotNull(compilers);
+ assertNotNull(targetVersions);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/KotlinTestParametersCollection.java b/src/test/java/com/android/tools/r8/KotlinTestParametersCollection.java
new file mode 100644
index 0000000..6851116
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/KotlinTestParametersCollection.java
@@ -0,0 +1,22 @@
+// Copyright (c) 2019, 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;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+public class KotlinTestParametersCollection implements Iterable<KotlinTestParameters> {
+
+ private final Collection<KotlinTestParameters> parameters;
+
+ public KotlinTestParametersCollection(Collection<KotlinTestParameters> parameters) {
+ assert parameters != null;
+ this.parameters = parameters;
+ }
+
+ @Override
+ public Iterator<KotlinTestParameters> iterator() {
+ return parameters.iterator();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index b2945dc..fe0aa6c 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -360,8 +360,6 @@
// Actually running Proguard should only be during development.
private static final boolean RUN_PROGUARD = System.getProperty("run_proguard") != null;
- // Actually running r8.jar in a forked process.
- private static final boolean RUN_R8_JAR = System.getProperty("run_r8_jar") != null;
@Rule public ExpectedException thrown = ExpectedException.none();
@@ -395,6 +393,10 @@
return TestParametersBuilder.builder();
}
+ public static KotlinTestParameters.Builder getKotlinTestParameters() {
+ return KotlinTestParameters.builder();
+ }
+
protected static <S, T, E extends Throwable> Function<S, T> memoizeFunction(
ThrowingFunction<S, T, E> fn) {
return CacheBuilder.newBuilder()
@@ -446,13 +448,6 @@
}
/**
- * Check if tests should run R8 in a forked process when applicable.
- */
- protected boolean isRunR8Jar() {
- return RUN_R8_JAR;
- }
-
- /**
* Write lines of text to a temporary file.
*
* The file will include a line separator after the last line.
@@ -1662,6 +1657,10 @@
return dexItemFactory.createType(descriptor(clazz));
}
+ public static DexType toDexType(ClassReference classReference, DexItemFactory dexItemFactory) {
+ return dexItemFactory.createType(classReference.getDescriptor());
+ }
+
public static String binaryName(Class<?> clazz) {
return DescriptorUtils.getBinaryNameFromJavaType(typeName(clazz));
}
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index b7ca275..27d643a 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -20,7 +20,6 @@
import com.android.tools.r8.utils.ThrowingOutputStream;
import com.android.tools.r8.utils.codeinspector.EnumUnboxingInspector;
import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
-import com.android.tools.r8.utils.codeinspector.HorizontallyMergedLambdaClassesInspector;
import com.android.tools.r8.utils.codeinspector.VerticallyMergedClassesInspector;
import com.google.common.base.Suppliers;
import java.io.ByteArrayOutputStream;
@@ -124,35 +123,24 @@
}
public T addHorizontallyMergedClassesInspector(
- Consumer<HorizontallyMergedClassesInspector> inspector) {
+ ThrowableConsumer<HorizontallyMergedClassesInspector> inspector) {
return addOptionsModification(
options ->
options.testing.horizontallyMergedClassesConsumer =
((dexItemFactory, horizontallyMergedClasses) ->
- inspector.accept(
+ inspector.acceptWithRuntimeException(
new HorizontallyMergedClassesInspector(
dexItemFactory, horizontallyMergedClasses))));
}
public T addHorizontallyMergedClassesInspectorIf(
- boolean condition, Consumer<HorizontallyMergedClassesInspector> inspector) {
+ boolean condition, ThrowableConsumer<HorizontallyMergedClassesInspector> inspector) {
if (condition) {
return addHorizontallyMergedClassesInspector(inspector);
}
return self();
}
- public T addHorizontallyMergedLambdaClassesInspector(
- Consumer<HorizontallyMergedLambdaClassesInspector> inspector) {
- return addOptionsModification(
- options ->
- options.testing.horizontallyMergedLambdaClassesConsumer =
- ((dexItemFactory, horizontallyMergedLambdaClasses) ->
- inspector.accept(
- new HorizontallyMergedLambdaClassesInspector(
- dexItemFactory, horizontallyMergedLambdaClasses))));
- }
-
public T addVerticallyMergedClassesInspector(
Consumer<VerticallyMergedClassesInspector> inspector) {
return addOptionsModification(
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 2216a2c..1629285 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -351,6 +351,10 @@
}
public T addKeepAttributes(String... attributes) {
+ return addKeepAttributes(Arrays.asList(attributes));
+ }
+
+ public T addKeepAttributes(List<String> attributes) {
return addKeepRules("-keepattributes " + String.join(",", attributes));
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java
index f878fd5..4d62a05 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java
@@ -36,9 +36,7 @@
options ->
options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addHorizontallyMergedClassesInspectorIf(
- enableHorizontalClassMerging,
- inspector ->
- inspector.assertMerged(A.class, B.class).assertMergedIntoDifferentType(B.class))
+ enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoHorizontalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessOnMergedClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessOnMergedClassTest.java
index ce0425e..029035e 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessOnMergedClassTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessOnMergedClassTest.java
@@ -28,12 +28,8 @@
.addOptionsModification(
options ->
options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
- .addHorizontallyMergedClassesInspector(
- inspector -> {
- if (enableHorizontalClassMerging) {
- inspector.assertMerged(C.class, D.class).assertMergedIntoDifferentType(D.class);
- }
- })
+ .addHorizontallyMergedClassesInspectorIf(
+ enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(D.class, C.class))
.enableNeverClassInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessWithMergedTypeTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessWithMergedTypeTest.java
index 79aae15..03b99e0 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessWithMergedTypeTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessWithMergedTypeTest.java
@@ -28,13 +28,9 @@
.addOptionsModification(
options ->
options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
- .addHorizontallyMergedClassesInspector(
- inspector -> {
- if (enableHorizontalClassMerging) {
- inspector.assertMerged(HelloGreeting.class, WorldGreeting.class);
- inspector.assertMergedIntoDifferentType(WorldGreeting.class);
- }
- })
+ .addHorizontallyMergedClassesInspectorIf(
+ enableHorizontalClassMerging,
+ inspector -> inspector.assertMergedInto(WorldGreeting.class, HelloGreeting.class))
.enableNeverClassInliningAnnotations()
.enableNoHorizontalClassMergingAnnotations()
.enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
index ff841d7..86e11d0 100644
--- a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
+++ b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
@@ -29,7 +29,7 @@
@Parameters(name = "{0}, kotlinc: {1}")
public static List<Object[]> setup() {
return buildParameters(
- TestParametersBuilder.builder().withAllRuntimes().withAllApiLevels().build(),
+ TestParametersBuilder.builder().withAllRuntimesAndApiLevels().build(),
getKotlinCompilers());
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
index aa5393a..55d4763 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.desugar.desugaredlibrary.kotlin;
import static com.android.tools.r8.KotlinTestBase.getCompileMemoizer;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
@@ -16,14 +15,13 @@
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase.KotlinCompileMemoizer;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.kotlin.KotlinMetadataWriter;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
@@ -45,30 +43,27 @@
public class KotlinMetadataTest extends DesugaredLibraryTestBase {
private static final String PKG = KotlinMetadataTest.class.getPackage().getName();
- private final TestParameters parameters;
- private final boolean shrinkDesugaredLibrary;
- private final KotlinTargetVersion targetVersion;
- private final KotlinCompiler kotlinCompiler;
private static final String EXPECTED_OUTPUT = "Wuhuu, my special day is: 1997-8-29-2-14";
- @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}, target: {2}, kotlinc: {3}")
+ private final TestParameters parameters;
+ private final KotlinTestParameters kotlinParameters;
+ private final boolean shrinkDesugaredLibrary;
+
+ @Parameters(name = "{0}, {1}, shrinkDesugaredLibrary: {2}")
public static List<Object[]> data() {
return buildParameters(
- BooleanUtils.values(),
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
}
public KotlinMetadataTest(
- boolean shrinkDesugaredLibrary,
TestParameters parameters,
- KotlinTargetVersion targetVersion,
- KotlinCompiler kotlinCompiler) {
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ KotlinTestParameters kotlinParameters,
+ boolean shrinkDesugaredLibrary) {
this.parameters = parameters;
- this.targetVersion = targetVersion;
- this.kotlinCompiler = kotlinCompiler;
+ this.kotlinParameters = kotlinParameters;
+ this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
}
private static KotlinCompileMemoizer compiledJars =
@@ -83,9 +78,9 @@
public void testCf() throws Exception {
assumeTrue(parameters.getRuntime().isCf());
testForRuntime(parameters)
- .addProgramFiles(compiledJars.getForConfiguration(kotlinCompiler, targetVersion))
- .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinCompiler))
- .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinCompiler))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinParameters))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinParameters.getCompiler()))
+ .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinParameters.getCompiler()))
.run(parameters.getRuntime(), PKG + ".MainKt")
.assertSuccessWithOutputLines(EXPECTED_OUTPUT);
}
@@ -97,9 +92,9 @@
final File output = temp.newFile("output.zip");
final D8TestRunResult d8TestRunResult =
testForD8()
- .addProgramFiles(compiledJars.getForConfiguration(kotlinCompiler, targetVersion))
- .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinCompiler))
- .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinCompiler))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinParameters))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinParameters.getCompiler()))
+ .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinParameters.getCompiler()))
.setProgramConsumer(new ArchiveConsumer(output.toPath(), true))
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -126,9 +121,9 @@
boolean desugarLibrary = parameters.isDexRuntime() && requiresAnyCoreLibDesugaring(parameters);
final R8FullTestBuilder testBuilder =
testForR8(parameters.getBackend())
- .addProgramFiles(compiledJars.getForConfiguration(kotlinCompiler, targetVersion))
- .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinCompiler))
- .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinCompiler))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinParameters))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinParameters.getCompiler()))
+ .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinParameters.getCompiler()))
.addKeepMainRule(PKG + ".MainKt")
.addKeepAllClassesRule()
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
diff --git a/src/test/java/com/android/tools/r8/desugar/lambdas/mergedcontext/MergedContextTest.java b/src/test/java/com/android/tools/r8/desugar/lambdas/mergedcontext/MergedContextTest.java
index 35e31d5..86d541e 100644
--- a/src/test/java/com/android/tools/r8/desugar/lambdas/mergedcontext/MergedContextTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/lambdas/mergedcontext/MergedContextTest.java
@@ -42,7 +42,7 @@
.setMinApi(parameters.getApiLevel())
.addHorizontallyMergedClassesInspector(
inspector -> {
- inspector.assertClassNotMerged(C.class);
+ inspector.assertClassesNotMerged(C.class);
inspector.assertMergedInto(B.class, A.class);
})
.run(parameters.getRuntime(), TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/kotlin/SimpleKotlinEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/kotlin/SimpleKotlinEnumUnboxingTest.java
index 3c48865..6f4b565 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/kotlin/SimpleKotlinEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/kotlin/SimpleKotlinEnumUnboxingTest.java
@@ -6,15 +6,13 @@
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static com.android.tools.r8.KotlinTestBase.getCompileMemoizer;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase.KotlinCompileMemoizer;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.enumunboxing.EnumUnboxingTestBase;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -29,10 +27,9 @@
public class SimpleKotlinEnumUnboxingTest extends EnumUnboxingTestBase {
private final TestParameters parameters;
+ private final KotlinTestParameters kotlinParameters;
private final boolean enumValueOptimization;
private final EnumKeepRules enumKeepRules;
- private final KotlinTargetVersion targetVersion;
- private final KotlinCompiler kotlinCompiler;
private static final String PKG = SimpleKotlinEnumUnboxingTest.class.getPackage().getName();
private static final KotlinCompileMemoizer jars =
@@ -43,27 +40,24 @@
DescriptorUtils.getBinaryNameFromJavaType(PKG),
"Main.kt"));
- @Parameters(name = "{0}, valueOpt: {1}, keep: {2}, kotlin targetVersion: {3}, kotlinc: {4}")
+ @Parameters(name = "{0}, {1}, valueOpt: {2}, keep: {3}")
public static List<Object[]> enumUnboxingTestParameters() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
BooleanUtils.values(),
- getAllEnumKeepRules(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getAllEnumKeepRules());
}
public SimpleKotlinEnumUnboxingTest(
TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
boolean enumValueOptimization,
- EnumKeepRules enumKeepRules,
- KotlinTargetVersion targetVersion,
- KotlinCompiler kotlinCompiler) {
+ EnumKeepRules enumKeepRules) {
this.parameters = parameters;
+ this.kotlinParameters = kotlinParameters;
this.enumValueOptimization = enumValueOptimization;
this.enumKeepRules = enumKeepRules;
- this.targetVersion = targetVersion;
- this.kotlinCompiler = kotlinCompiler;
}
@Test
@@ -71,8 +65,8 @@
assumeTrue(parameters.isDexRuntime());
testForR8(parameters.getBackend())
.addProgramFiles(
- jars.getForConfiguration(kotlinCompiler, targetVersion),
- ToolHelper.getKotlinStdlibJar(kotlinCompiler))
+ jars.getForConfiguration(kotlinParameters),
+ ToolHelper.getKotlinStdlibJar(kotlinParameters.getCompiler()))
.addKeepMainRule(PKG + ".MainKt")
.addKeepRules(enumKeepRules.getKeepRules())
.addKeepRuntimeVisibleAnnotations()
diff --git a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
index 0abfe16..0fb02d7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -14,19 +14,17 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.ThrowableConsumer;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.jasmin.JasminBuilder;
import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -52,16 +50,13 @@
private final List<Path> extraClasspath = new ArrayList<>();
// Some tests defined in subclasses, e.g., Metadata tests, don't care about access relaxation.
- protected AbstractR8KotlinTestBase(
- KotlinTargetVersion kotlinTargetVersion, KotlinCompiler kotlinc) {
- this(kotlinTargetVersion, kotlinc, false);
+ protected AbstractR8KotlinTestBase(KotlinTestParameters kotlinParameters) {
+ this(kotlinParameters, false);
}
protected AbstractR8KotlinTestBase(
- KotlinTargetVersion kotlinTargetVersion,
- KotlinCompiler kotlinc,
- boolean allowAccessModification) {
- super(kotlinTargetVersion, kotlinc);
+ KotlinTestParameters kotlinParameters, boolean allowAccessModification) {
+ super(kotlinParameters);
this.allowAccessModification = allowAccessModification;
}
@@ -142,15 +137,6 @@
return fieldSubject;
}
- protected void checkFieldIsRemoved(
- ClassSubject classSubject, String fieldType, String fieldName) {
- // Field must exist in the input.
- checkFieldPresenceInInput(classSubject.getOriginalName(), fieldType, fieldName, true);
- FieldSubject fieldSubject = classSubject.field(fieldType, fieldName);
- assertNotNull(fieldSubject);
- assertThat(fieldSubject, not(isPresent()));
- }
-
protected void checkFieldIsAbsent(ClassSubject classSubject, String fieldType, String fieldName) {
// Field must NOT exist in the input.
checkFieldPresenceInInput(classSubject.getOriginalName(), fieldType, fieldName, false);
@@ -159,12 +145,6 @@
assertFalse(fieldSubject.isPresent());
}
- protected FieldSubject checkFieldIsAbsent(ClassSubject classSubject, String fieldName) {
- FieldSubject fieldSubject = classSubject.uniqueFieldWithName(fieldName);
- assertThat(fieldSubject, not(isPresent()));
- return fieldSubject;
- }
-
protected void checkMethodIsAbsent(ClassSubject classSubject, MethodSignature methodSignature) {
checkMethodPresenceInInput(classSubject.getOriginalName(), methodSignature, false);
checkMethodPresenceInOutput(classSubject, methodSignature, false);
@@ -187,11 +167,6 @@
checkMethodIsKeptOrRemoved(classSubject, methodSignature, false);
}
- protected void checkMethodIsRemoved(ClassSubject classSubject, String methodName) {
- MethodSubject methodSubject = classSubject.uniqueMethodWithName(methodName);
- assertThat(methodSubject, not(isPresent()));
- }
-
protected MethodSubject checkMethodIsKeptOrRemoved(
ClassSubject classSubject, MethodSignature methodSignature, boolean isPresent) {
checkMethodPresenceInInput(classSubject.getOriginalName(), methodSignature, true);
@@ -266,14 +241,13 @@
.addProgramFiles(classpath)
.addKeepMainRule(mainClass)
.allowAccessModification(allowAccessModification)
- .allowDiagnosticMessages()
+ .allowDiagnosticWarningMessages()
.enableProguardTestOptions()
.noMinification()
.apply(configuration)
.compile()
.assertAllWarningMessagesMatch(
containsString("Resource 'META-INF/MANIFEST.MF' already exists."))
- .assertAllInfoMessagesMatch(containsString("Unrecognized Kotlin lambda "))
.run(mainClass)
.assertSuccessWithOutput(javaResult.stdout);
}
@@ -308,12 +282,6 @@
}
}
- @FunctionalInterface
- public interface AndroidAppInspector {
-
- void inspectApp(AndroidApp androidApp) throws Exception;
- }
-
/**
* Generates a "main" class which invokes the given static method (which has no argument and
* return void type). This new class is then added to the test classpath.
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
index e4622be..608b92b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
@@ -4,28 +4,20 @@
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
-import com.android.tools.r8.R8FullTestBuilder;
-import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.KotlinTestParametersCollection;
import com.android.tools.r8.TestShrinkerBuilder;
-import com.android.tools.r8.ThrowableConsumer;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.code.NewInstance;
import com.android.tools.r8.code.SgetObject;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -33,7 +25,6 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
-import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
@@ -46,29 +37,27 @@
@RunWith(Parameterized.class)
public class KotlinClassInlinerTest extends AbstractR8KotlinTestBase {
- @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
- public static Collection<Object[]> data() {
- return buildParameters(
- KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
+ @Parameterized.Parameters(name = "{0}")
+ public static KotlinTestParametersCollection data() {
+ return getKotlinTestParameters().withAllCompilersAndTargetVersions().build();
}
- public KotlinClassInlinerTest(
- KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ public KotlinClassInlinerTest(KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters, true);
}
private static boolean isLambda(DexClass clazz) {
- return !clazz.type.getPackageDescriptor().startsWith("kotlin") &&
- (isKStyleLambdaOrGroup(clazz) || isJStyleLambdaOrGroup(clazz));
+ return !clazz.getType().getPackageDescriptor().startsWith("kotlin")
+ && (isKStyleLambda(clazz) || isJStyleLambda(clazz));
}
- private static boolean isKStyleLambdaOrGroup(DexClass clazz) {
- return clazz.superType.descriptor.toString().equals("Lkotlin/jvm/internal/Lambda;");
+ private static boolean isKStyleLambda(DexClass clazz) {
+ return clazz.getSuperType().getTypeName().equals("kotlin.jvm.internal.Lambda");
}
- private static boolean isJStyleLambdaOrGroup(DexClass clazz) {
- return clazz.superType.descriptor.toString().equals("Ljava/lang/Object;") &&
- clazz.interfaces.size() == 1;
+ private static boolean isJStyleLambda(DexClass clazz) {
+ return clazz.getSuperType().getTypeName().equals(Object.class.getTypeName())
+ && clazz.getInterfaces().size() == 1;
}
private static Predicate<DexType> createLambdaCheck(CodeInspector inspector) {
@@ -82,9 +71,8 @@
@Test
public void testJStyleLambdas() throws Exception {
- assumeTrue("Only work with -allowaccessmodification", allowAccessModification);
- final String mainClassName = "class_inliner_lambda_j_style.MainKt";
- runTestWithDefaults(
+ String mainClassName = "class_inliner_lambda_j_style.MainKt";
+ runTest(
"class_inliner_lambda_j_style",
mainClassName,
testBuilder ->
@@ -92,21 +80,32 @@
// TODO(jsjeon): Introduce @NeverInline to kotlinR8TestResources
.addKeepRules("-neverinline class * { void test*State*(...); }")
.addDontWarnJetBrainsNotNullAnnotation()
+ .addHorizontallyMergedClassesInspector(
+ inspector ->
+ inspector
+ .assertIsCompleteMergeGroup(
+ "class_inliner_lambda_j_style.MainKt$testStateless$1",
+ "class_inliner_lambda_j_style.MainKt$testStateless$2",
+ "class_inliner_lambda_j_style.MainKt$testStateless$3")
+ .assertIsCompleteMergeGroup(
+ "class_inliner_lambda_j_style.MainKt$testStateful$1",
+ "class_inliner_lambda_j_style.MainKt$testStateful$2",
+ "class_inliner_lambda_j_style.MainKt$testStateful$2$1",
+ "class_inliner_lambda_j_style.MainKt$testStateful$3",
+ "class_inliner_lambda_j_style.MainKt$testStateful2$1",
+ "class_inliner_lambda_j_style.MainKt$testStateful3$1"))
.noClassInlining())
.inspect(
inspector -> {
assertThat(
+ inspector.clazz("class_inliner_lambda_j_style.MainKt$testStateless$1"),
+ isPresent());
+ assertThat(
inspector.clazz("class_inliner_lambda_j_style.MainKt$testStateful$1"),
isPresent());
- assertThat(
- inspector.clazz("class_inliner_lambda_j_style.MainKt$testStateful2$1"),
- isPresent());
- assertThat(
- inspector.clazz("class_inliner_lambda_j_style.MainKt$testStateful3$1"),
- isPresent());
});
- runTestWithDefaults(
+ runTest(
"class_inliner_lambda_j_style",
mainClassName,
testBuilder ->
@@ -116,40 +115,22 @@
.addDontWarnJetBrainsNotNullAnnotation())
.inspect(
inspector -> {
- Predicate<DexType> lambdaCheck = createLambdaCheck(inspector);
- ClassSubject clazz = inspector.clazz(mainClassName);
+ // TODO(b/173337498): MainKt$testStateless$1 should be class inlined.
+ assertThat(
+ inspector.clazz("class_inliner_lambda_j_style.MainKt$testStateless$1"),
+ isPresent());
- assertEquals(
- Sets.newHashSet(), collectAccessedTypes(lambdaCheck, clazz, "testStateless"));
-
- assertEquals(
- Sets.newHashSet(), collectAccessedTypes(lambdaCheck, clazz, "testStateful"));
-
+ // TODO(b/173337498): MainKt$testStateful$1 should be class inlined.
assertThat(
inspector.clazz("class_inliner_lambda_j_style.MainKt$testStateful$1"),
- not(isPresent()));
-
- assertEquals(
- Sets.newHashSet(), collectAccessedTypes(lambdaCheck, clazz, "testStateful2"));
-
- assertThat(
- inspector.clazz("class_inliner_lambda_j_style.MainKt$testStateful2$1"),
- not(isPresent()));
-
- assertEquals(
- Sets.newHashSet(), collectAccessedTypes(lambdaCheck, clazz, "testStateful3"));
-
- assertThat(
- inspector.clazz("class_inliner_lambda_j_style.MainKt$testStateful3$1"),
- not(isPresent()));
+ isPresent());
});
}
@Test
public void testKStyleLambdas() throws Exception {
- assumeTrue("Only work with -allowaccessmodification", allowAccessModification);
- final String mainClassName = "class_inliner_lambda_k_style.MainKt";
- runTestWithDefaults(
+ String mainClassName = "class_inliner_lambda_k_style.MainKt";
+ runTest(
"class_inliner_lambda_k_style",
mainClassName,
testBuilder ->
@@ -160,6 +141,15 @@
"-neverinline class * { void testBigExtraMethod(...); }",
"-neverinline class * { void testBigExtraMethodReturningLambda(...); }")
.addDontWarnJetBrainsAnnotations()
+ .addHorizontallyMergedClassesInspector(
+ inspector ->
+ inspector.assertIsCompleteMergeGroup(
+ "class_inliner_lambda_k_style.MainKt$testBigExtraMethod$1",
+ "class_inliner_lambda_k_style.MainKt$testBigExtraMethod2$1",
+ "class_inliner_lambda_k_style.MainKt$testBigExtraMethod3$1",
+ "class_inliner_lambda_k_style.MainKt$testBigExtraMethodReturningLambda$1",
+ "class_inliner_lambda_k_style.MainKt$testBigExtraMethodReturningLambda2$1",
+ "class_inliner_lambda_k_style.MainKt$testBigExtraMethodReturningLambda3$1"))
.noClassInlining())
.inspect(
inspector -> {
@@ -174,27 +164,9 @@
assertThat(
inspector.clazz("class_inliner_lambda_k_style.MainKt$testBigExtraMethod$1"),
isPresent());
- assertThat(
- inspector.clazz("class_inliner_lambda_k_style.MainKt$testBigExtraMethod2$1"),
- isPresent());
- assertThat(
- inspector.clazz("class_inliner_lambda_k_style.MainKt$testBigExtraMethod3$1"),
- isPresent());
- assertThat(
- inspector.clazz(
- "class_inliner_lambda_k_style.MainKt$testBigExtraMethodReturningLambda$1"),
- isPresent());
- assertThat(
- inspector.clazz(
- "class_inliner_lambda_k_style.MainKt$testBigExtraMethodReturningLambda2$1"),
- isPresent());
- assertThat(
- inspector.clazz(
- "class_inliner_lambda_k_style.MainKt$testBigExtraMethodReturningLambda3$1"),
- isPresent());
});
- runTestWithDefaults(
+ runTest(
"class_inliner_lambda_k_style",
mainClassName,
testBuilder ->
@@ -207,20 +179,6 @@
.addDontWarnJetBrainsAnnotations())
.inspect(
inspector -> {
- Predicate<DexType> lambdaCheck = createLambdaCheck(inspector);
- ClassSubject clazz = inspector.clazz(mainClassName);
-
- // TODO(b/173337498): Should be empty, but horizontal class merging interferes with
- // class inlining.
- assertEquals(
- Sets.newHashSet(
- "class_inliner_lambda_k_style.MainKt$testKotlinSequencesStateless$1"),
- collectAccessedTypes(
- lambdaCheck,
- clazz,
- "testKotlinSequencesStateless",
- "kotlin.sequences.Sequence"));
-
// TODO(b/173337498): Should be absent, but horizontal class merging interferes with
// class inlining.
assertThat(
@@ -228,19 +186,6 @@
"class_inliner_lambda_k_style.MainKt$testKotlinSequencesStateless$1"),
isPresent());
- // TODO(b/173337498): Should be empty, but horizontal class merging interferes with
- // class inlining.
- assertEquals(
- Sets.newHashSet(
- "class_inliner_lambda_k_style.MainKt$testKotlinSequencesStateful$1"),
- collectAccessedTypes(
- lambdaCheck,
- clazz,
- "testKotlinSequencesStateful",
- "int",
- "int",
- "kotlin.sequences.Sequence"));
-
// TODO(b/173337498): Should be absent, but horizontal class merging interferes with
// class inlining.
assertThat(
@@ -248,57 +193,33 @@
"class_inliner_lambda_k_style.MainKt$testKotlinSequencesStateful$1"),
isPresent());
- assertEquals(
- Sets.newHashSet(),
- collectAccessedTypes(lambdaCheck, clazz, "testBigExtraMethod"));
-
+ // TODO(b/173337498): Should be absent, but horizontal class merging interferes with
+ // class inlining.
assertThat(
inspector.clazz("class_inliner_lambda_k_style.MainKt$testBigExtraMethod$1"),
- not(isPresent()));
- assertThat(
- inspector.clazz("class_inliner_lambda_k_style.MainKt$testBigExtraMethod2$1"),
- not(isPresent()));
- assertThat(
- inspector.clazz("class_inliner_lambda_k_style.MainKt$testBigExtraMethod3$1"),
- not(isPresent()));
-
- assertEquals(
- Sets.newHashSet(),
- collectAccessedTypes(lambdaCheck, clazz, "testBigExtraMethodReturningLambda"));
-
- assertThat(
- inspector.clazz(
- "class_inliner_lambda_k_style.MainKt$testBigExtraMethodReturningLambda$1"),
- not(isPresent()));
- assertThat(
- inspector.clazz(
- "class_inliner_lambda_k_style.MainKt$testBigExtraMethodReturningLambda2$1"),
- not(isPresent()));
- assertThat(
- inspector.clazz(
- "class_inliner_lambda_k_style.MainKt$testBigExtraMethodReturningLambda3$1"),
- not(isPresent()));
+ isPresent());
});
}
@Test
public void testDataClass() throws Exception {
- assumeTrue("Only work with -allowaccessmodification", allowAccessModification);
- final String mainClassName = "class_inliner_data_class.MainKt";
- runTestWithDefaults(
+ String mainClassName = "class_inliner_data_class.MainKt";
+ runTest(
"class_inliner_data_class",
mainClassName,
TestShrinkerBuilder::addDontWarnJetBrainsAnnotations)
.inspect(
inspector -> {
ClassSubject clazz = inspector.clazz(mainClassName);
- assertTrue(
+
+ // TODO(b/141719453): Data class should maybe be class inlined.
+ assertEquals(
+ Sets.newHashSet("class_inliner_data_class.Alpha"),
collectAccessedTypes(
- type -> !type.toSourceString().startsWith("java."),
- clazz,
- "main",
- String[].class.getCanonicalName())
- .isEmpty());
+ type -> !type.toSourceString().startsWith("java."),
+ clazz,
+ "main",
+ String[].class.getCanonicalName()));
assertEquals(
Lists.newArrayList(
"void kotlin.jvm.internal.Intrinsics.throwParameterIsNullException(java.lang.String)"),
@@ -325,39 +246,6 @@
.collect(Collectors.toSet());
}
- private R8TestRunResult runTestWithDefaults(String folder, String mainClass) throws Exception {
- return runTestWithDefaults(folder, mainClass, null);
- }
-
- private R8TestRunResult runTestWithDefaults(
- String folder, String mainClass, ThrowableConsumer<R8FullTestBuilder> configuration)
- throws Exception {
- return runTest(
- folder,
- mainClass,
- testBuilder ->
- testBuilder
- .addOptionsModification(
- options -> {
- options.enableInlining = true;
- options.enableLambdaMerging = false;
-
- // TODO(b/141719453): These limits should be removed if a possible or the test
- // refactored. Tests check if specific lambdas are inlined or not, where some
- // of target lambdas have at least 4 instructions.
- options.inliningInstructionLimit = 4;
- options.classInliningInstructionLimit = 40;
-
- // Class inlining depends on the processing order. We therefore insert all
- // call graph edges and verify that we can class inline everything under this
- // condition.
- options.testing.addCallEdgesForLibraryInvokes = true;
-
- options.horizontalClassMergerOptions().disableKotlinLambdaMerging();
- })
- .apply(configuration));
- }
-
private List<String> collectStaticCalls(ClassSubject clazz, String methodName, String... params) {
assertNotNull(clazz);
MethodSignature signature = new MethodSignature(methodName, "void", params);
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassStaticizerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassStaticizerTest.java
index e5d0d09..1598bb8 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassStaticizerTest.java
@@ -4,16 +4,14 @@
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8TestRunResult;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
@@ -26,15 +24,16 @@
@RunWith(Parameterized.class)
public class KotlinClassStaticizerTest extends AbstractR8KotlinTestBase {
- @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
+ @Parameterized.Parameters(name = "{0}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
}
public KotlinClassStaticizerTest(
- KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ KotlinTestParameters kotlinParameters, boolean allowAccessModification) {
+ super(kotlinParameters, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinDuplicateAnnotationTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinDuplicateAnnotationTest.java
index 7407d46..e74d082 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinDuplicateAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinDuplicateAnnotationTest.java
@@ -3,16 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
@@ -36,12 +34,11 @@
o.enableInlining = false;
};
- @Parameterized.Parameters(name = "{0} target: {1}, kotlinc: {2}, allowAccessModification: {3}")
+ @Parameterized.Parameters(name = "{0}, {1}, allowAccessModification: {2}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
BooleanUtils.values());
}
@@ -49,10 +46,9 @@
public KotlinDuplicateAnnotationTest(
TestParameters parameters,
- KotlinTargetVersion targetVersion,
- KotlinCompiler kotlinc,
+ KotlinTestParameters kotlinParameters,
boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ super(kotlinParameters, allowAccessModification);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
index eb1ca57..dae8a7d 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
@@ -3,15 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -26,12 +24,11 @@
private static final String FOLDER = "intrinsics";
private static final String MAIN = FOLDER + ".InlineKt";
- @Parameterized.Parameters(name = "{0} target: {1}, kotlinc: {2}, allowAccessModification: {3}")
+ @Parameterized.Parameters(name = "{0}, {1}, allowAccessModification: {2}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
BooleanUtils.values());
}
@@ -39,10 +36,9 @@
public KotlinIntrinsicsInlineTest(
TestParameters parameters,
- KotlinTargetVersion targetVersion,
- KotlinCompiler kotlinc,
+ KotlinTestParameters kotlinParameters,
boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ super(kotlinParameters, allowAccessModification);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java
index 5e25b92..fa3b505 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java
@@ -3,15 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestShrinkerBuilder;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
@@ -23,15 +21,16 @@
@RunWith(Parameterized.class)
public class KotlinUnusedArgumentsInLambdasTest extends AbstractR8KotlinTestBase {
- @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
+ @Parameterized.Parameters(name = "{0}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
}
public KotlinUnusedArgumentsInLambdasTest(
- KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ KotlinTestParameters kotlinParameters, boolean allowAccessModification) {
+ super(kotlinParameters, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java
index 6a8e196..226fb8b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java
@@ -3,16 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestShrinkerBuilder;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.FieldSubject;
@@ -28,18 +26,19 @@
@RunWith(Parameterized.class)
public class KotlinUnusedSingletonTest extends AbstractR8KotlinTestBase {
- @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "{0}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
}
private static final String printlnSignature =
"void java.io.PrintStream.println(java.lang.Object)";
public KotlinUnusedSingletonTest(
- KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ KotlinTestParameters kotlinParameters, boolean allowAccessModification) {
+ super(kotlinParameters, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
index 3137d61..9f92a95 100644
--- a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
@@ -3,16 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestShrinkerBuilder;
import com.android.tools.r8.ThrowableConsumer;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import java.util.Collection;
import org.junit.Test;
@@ -24,17 +22,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public ProcessKotlinReflectionLibTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
index 7166aed..c2c68e4 100644
--- a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
@@ -3,16 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestShrinkerBuilder;
import com.android.tools.r8.ThrowableConsumer;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.google.common.collect.ImmutableList;
import java.util.Collection;
@@ -24,17 +22,15 @@
public class ProcessKotlinStdlibTest extends KotlinTestBase {
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
- public ProcessKotlinStdlibTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ public ProcessKotlinStdlibTest(TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
@@ -71,22 +67,6 @@
}
@Test
- public void testDontShrinkAndDontOptimizeDifferently() throws Exception {
- test(
- ImmutableList.of("-keep,allowobfuscation class **.*Exception*"),
- tb ->
- tb.addDontWarnJetBrainsAnnotations()
- .noTreeShaking()
- .addOptionsModification(
- o -> {
- // Randomly choose a couple of optimizations.
- o.enableClassInlining = false;
- o.enableLambdaMerging = false;
- o.enableValuePropagation = false;
- }));
- }
-
- @Test
public void testDontShrinkAndDontObfuscate() throws Exception {
test(
ImmutableList.of("-dontshrink", "-dontobfuscate"),
@@ -99,13 +79,6 @@
}
@Test
- public void testDontShrinkDifferently() throws Exception {
- test(
- ImmutableList.of("-keep,allowobfuscation class **.*Exception*"),
- tb -> tb.addDontWarnJetBrainsAnnotations().noTreeShaking());
- }
-
- @Test
public void testDontOptimize() throws Exception {
test(ImmutableList.of("-dontoptimize"));
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
index 882bc22..a405400 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
@@ -4,16 +4,14 @@
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestShrinkerBuilder;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.jasmin.JasminBuilder;
import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
@@ -68,15 +66,16 @@
.addProperty("property", JAVA_LANG_STRING, Visibility.PRIVATE)
.addProperty("indirectPropertyGetter", JAVA_LANG_STRING, Visibility.PRIVATE);
- @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
+ @Parameterized.Parameters(name = "{0}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
}
public R8KotlinAccessorTest(
- KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ KotlinTestParameters kotlinParameters, boolean allowAccessModification) {
+ super(kotlinParameters, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
index 3faf486..b2f0927 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
@@ -4,10 +4,7 @@
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.kotlin.TestKotlinClass.Visibility;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -45,15 +42,16 @@
private Consumer<InternalOptions> disableClassInliner = o -> o.enableClassInlining = false;
- @Parameterized.Parameters(name = "target: {0}, kotlinc: {2}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "{0}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
}
public R8KotlinDataClassTest(
- KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ KotlinTestParameters kotlinParameters, boolean allowAccessModification) {
+ super(kotlinParameters, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
index 934ee16..11d1ea2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
@@ -4,10 +4,7 @@
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -26,15 +23,16 @@
private static final TestKotlinDataClass KOTLIN_INTRINSICS_CLASS =
new TestKotlinDataClass("kotlin.jvm.internal.Intrinsics");
- @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
+ @Parameterized.Parameters(name = "{0}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
}
public R8KotlinIntrinsicsTest(
- KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ KotlinTestParameters kotlinParameters, boolean allowAccessModification) {
+ super(kotlinParameters, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
index b9fefbaf4..edd2c8f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
@@ -4,11 +4,9 @@
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.kotlin.TestKotlinClass.Visibility;
import com.android.tools.r8.naming.MemberNaming;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -95,15 +93,16 @@
o.enableClassStaticizer = false;
};
- @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "{0}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
}
public R8KotlinPropertiesTest(
- KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ KotlinTestParameters kotlinParameters, boolean allowAccessModification) {
+ super(kotlinParameters, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
index 64e3a80..c9fd417 100644
--- a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
@@ -3,11 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -23,15 +21,16 @@
private static final String FOLDER = "non_null";
private static final String STRING = "java.lang.String";
- @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
+ @Parameterized.Parameters(name = "{0}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
}
public SimplifyIfNotNullKotlinTest(
- KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ KotlinTestParameters kotlinParameters, boolean allowAccessModification) {
+ super(kotlinParameters, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/coroutines/KotlinxCoroutinesTestRunner.java b/src/test/java/com/android/tools/r8/kotlin/coroutines/KotlinxCoroutinesTestRunner.java
index 4a05b76..1241446 100644
--- a/src/test/java/com/android/tools/r8/kotlin/coroutines/KotlinxCoroutinesTestRunner.java
+++ b/src/test/java/com/android/tools/r8/kotlin/coroutines/KotlinxCoroutinesTestRunner.java
@@ -4,13 +4,11 @@
package com.android.tools.r8.kotlin.coroutines;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.kotlin.metadata.KotlinMetadataTestBase;
import com.android.tools.r8.utils.ZipUtils;
@@ -50,19 +48,18 @@
private Set<String> notWorkingTests =
Sets.newHashSet("kotlinx.coroutines.test.TestDispatchersTest");
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
private final TestParameters parameters;
public KotlinxCoroutinesTestRunner(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/JStyleKotlinLambdaMergingWithEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/JStyleKotlinLambdaMergingWithEnumUnboxingTest.java
index 7103667..787ae1f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/JStyleKotlinLambdaMergingWithEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/JStyleKotlinLambdaMergingWithEnumUnboxingTest.java
@@ -9,13 +9,9 @@
import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NoHorizontalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.ir.optimize.lambda.kotlin.JStyleLambdaGroupIdFactory;
-import com.android.tools.r8.ir.optimize.lambda.kotlin.KotlinLambdaGroupIdFactory;
import com.android.tools.r8.kotlin.lambda.JStyleKotlinLambdaMergingWithEnumUnboxingTest.Main.EnumUnboxingCandidate;
import java.util.List;
import org.junit.Test;
@@ -49,31 +45,17 @@
.addDefaultRuntimeLibrary(parameters)
.addLibraryFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addKeepMainRule(Main.class)
- .addOptionsModification(
- options ->
- options.testing.kotlinLambdaMergerFactoryForClass =
- this::getKotlinLambdaMergerFactoryForClass)
- .addHorizontallyMergedLambdaClassesInspector(
- inspector -> inspector.assertMerged(Lambda1.class, Lambda2.class))
+ .addHorizontallyMergedClassesInspector(
+ inspector -> inspector.assertMergedInto(Lambda2.class, Lambda1.class))
.addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(EnumUnboxingCandidate.class))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableNoHorizontalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("Lambda1.method()", "Lambda2.method()");
}
- private KotlinLambdaGroupIdFactory getKotlinLambdaMergerFactoryForClass(DexProgramClass clazz) {
- String typeName = clazz.getType().toSourceString();
- if (typeName.equals(Lambda1.class.getTypeName())
- || typeName.equals(Lambda2.class.getTypeName())) {
- return JStyleLambdaGroupIdFactory.getInstance();
- }
- return null;
- }
-
static class Main {
@NeverClassInline
@@ -121,7 +103,6 @@
}
@NeverClassInline
- @NoHorizontalClassMerging
public static final class Lambda2 implements I {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java
index aea188c..fe0ef77 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java
@@ -9,13 +9,9 @@
import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NoHorizontalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.ir.optimize.lambda.kotlin.KStyleLambdaGroupIdFactory;
-import com.android.tools.r8.ir.optimize.lambda.kotlin.KotlinLambdaGroupIdFactory;
import com.android.tools.r8.kotlin.lambda.KStyleKotlinLambdaMergingWithEnumUnboxingTest.Main.EnumUnboxingCandidate;
import java.util.List;
import org.junit.Test;
@@ -48,17 +44,12 @@
.addInnerClasses(getClass())
.addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addKeepMainRule(Main.class)
- .addOptionsModification(
- options ->
- options.testing.kotlinLambdaMergerFactoryForClass =
- this::getKotlinLambdaMergerFactoryForClass)
- .addHorizontallyMergedLambdaClassesInspector(
- inspector -> inspector.assertMerged(Lambda1.class, Lambda2.class))
+ .addHorizontallyMergedClassesInspector(
+ inspector -> inspector.assertMergedInto(Lambda2.class, Lambda1.class))
.addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(EnumUnboxingCandidate.class))
.addDontWarnJetBrainsNotNullAnnotation()
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableNoHorizontalClassMergingAnnotations()
.noMinification()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -66,15 +57,6 @@
.assertSuccessWithOutputLines("Lambda1.method()", "Lambda2.method()");
}
- private KotlinLambdaGroupIdFactory getKotlinLambdaMergerFactoryForClass(DexProgramClass clazz) {
- String typeName = clazz.getType().toSourceString();
- if (typeName.equals(Lambda1.class.getTypeName())
- || typeName.equals(Lambda2.class.getTypeName())) {
- return KStyleLambdaGroupIdFactory.getInstance();
- }
- return null;
- }
-
static class Main {
@NeverClassInline
@@ -123,7 +105,6 @@
}
@NeverClassInline
- @NoHorizontalClassMerging
public static final class Lambda2 extends kotlin.jvm.internal.Lambda<kotlin.Unit>
implements kotlin.jvm.functions.Function0<kotlin.Unit> {
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java
index 4f78df2..655ddb5 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java
@@ -3,16 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.lambda;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
import com.android.tools.r8.utils.DescriptorUtils;
import java.nio.file.Path;
@@ -26,17 +24,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public KotlinLambdaMergerValidationTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc, false);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters, false);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java
new file mode 100644
index 0000000..0a49461
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingCapturesKotlinStyleTest.java
@@ -0,0 +1,161 @@
+// Copyright (c) 2018, 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.kotlin.lambda;
+
+import static com.android.tools.r8.utils.PredicateUtils.not;
+import static junit.framework.TestCase.assertEquals;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KotlinLambdaMergingCapturesKotlinStyleTest extends KotlinTestBase {
+
+ private final boolean allowAccessModification;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}, {1}, allow access modification: {2}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters()
+ .withCfRuntime(CfVm.last())
+ .withDexRuntime(Version.last())
+ .withAllApiLevels()
+ .build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
+ }
+
+ public KotlinLambdaMergingCapturesKotlinStyleTest(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean allowAccessModification) {
+ super(kotlinParameters);
+ this.allowAccessModification = allowAccessModification;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testJVM() throws Exception {
+ assumeFalse(allowAccessModification);
+ assumeTrue(parameters.isCfRuntime());
+ assumeTrue(kotlinParameters.isFirst());
+ testForJvm()
+ .addProgramFiles(getProgramFiles())
+ .run(parameters.getRuntime(), getMainClassName())
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramFiles(getProgramFiles())
+ .addKeepMainRule(getMainClassName())
+ .addDontWarnJetBrainsAnnotations()
+ .addHorizontallyMergedClassesInspector(this::inspect)
+ .allowAccessModification(allowAccessModification)
+ .allowDiagnosticWarningMessages()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .assertAllWarningMessagesMatch(
+ containsString("Resource 'META-INF/MANIFEST.MF' already exists."))
+ .run(parameters.getRuntime(), getMainClassName())
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+
+ private void inspect(HorizontallyMergedClassesInspector inspector) throws IOException {
+ // Get the Kotlin lambdas in the input.
+ KotlinLambdasInInput lambdasInInput =
+ KotlinLambdasInInput.create(getProgramFiles(), getTestName());
+ assertEquals(0, lambdasInInput.getNumberOfJStyleLambdas());
+ assertEquals(26, lambdasInInput.getNumberOfKStyleLambdas());
+
+ // Only a subset of all K-style Kotlin lambdas are merged.
+ Set<ClassReference> unmergedLambdas =
+ ImmutableSet.of(
+ lambdasInInput.getKStyleLambdaReferenceFromTypeName(getTestName(), "MainKt$test1$15"),
+ lambdasInInput.getKStyleLambdaReferenceFromTypeName(getTestName(), "MainKt$test2$9"),
+ lambdasInInput.getKStyleLambdaReferenceFromTypeName(getTestName(), "MainKt$test2$10"),
+ lambdasInInput.getKStyleLambdaReferenceFromTypeName(getTestName(), "MainKt$test2$11"));
+ inspector
+ .assertClassReferencesMerged(
+ lambdasInInput.getKStyleLambdas().stream()
+ .filter(not(unmergedLambdas::contains))
+ .collect(Collectors.toList()))
+ .assertClassReferencesNotMerged(unmergedLambdas);
+ }
+
+ private String getExpectedOutput() {
+ return StringUtils.lines(
+ "a: 1 2 3",
+ "b: 2 3 1",
+ "c: 3 1 2",
+ "d: 1 A D(d=x)",
+ "e: 2 D(d=y) B",
+ "f: 3 D(d=z) D(d=x)",
+ "g: 7 D(d=z) 3",
+ "h: 8 9 1",
+ "i: A B C",
+ "j: D(d=x) D(d=y) D(d=z)",
+ "k: 7 8 9",
+ "l: A D(d=y) 9",
+ "n: 7 B D(d=z)",
+ "o: D(d=x) 8 C",
+ "p: 1 2 C",
+ "a: true 10 * 20 30 40 50.0 60.0 D(d=D) S null 70",
+ "a: true 10 D(d=D) S * 20 30 40 50.0 60.0 null 70",
+ "a: true * 20 40 50.0 60.0 S null 70 10 30 D(d=D)",
+ "a: D(d=D) S null 70 true 10 * 20 30 40 50.0 60.0",
+ "a: true 10 * 20 30 40 50.0 60.0 D(d=D) S $o3 $o4",
+ "a: true 10 * 20 30 40 50.0 60.0 D(d=D) $o2 $o3 70",
+ "a: true 10 * 20 30 40 50.0 60.0 $o1 $o2 null 70",
+ "a: true 10 * 20 30 40 50.0 60.0 $o1 S null $o4",
+ "x: true 10 * 20 30 40 50.0 60.0 D(d=D) S $o3 70",
+ "y: true 10 * 20 30 40 $f 60.0 D(d=D) S null 70",
+ "z: true 10 * $s 30 40 50.0 60.0 D(d=D) S null 70");
+ }
+
+ private Path getJavaJarFile() {
+ return getJavaJarFile(getTestName());
+ }
+
+ private String getMainClassName() {
+ return getTestName() + ".MainKt";
+ }
+
+ private List<Path> getProgramFiles() {
+ Path kotlinJarFile =
+ getCompileMemoizer(getKotlinFilesInResource(getTestName()), getTestName())
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect())
+ .getForConfiguration(kotlinc, targetVersion);
+ return ImmutableList.of(kotlinJarFile, getJavaJarFile());
+ }
+
+ private String getTestName() {
+ return "lambdas_kstyle_captures";
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingDebugTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingDebugTest.java
index 9cee958..61f417e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingDebugTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingDebugTest.java
@@ -3,11 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.lambda;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.hamcrest.CoreMatchers.equalTo;
import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
@@ -24,14 +23,19 @@
private static final String FOLDER = "reprocess_merged_lambdas_kstyle";
private static final String MAIN_CLASS = "reprocess_merged_lambdas_kstyle.MainKt";
- @Parameters(name = "{0}")
+ @Parameters(name = "{0}, {1}")
public static List<Object[]> data() {
return buildParameters(
- getTestParameters().withDexRuntimes().withAllApiLevels().build(), getKotlinCompilers());
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getKotlinTestParameters()
+ .withAllCompilers()
+ .withTargetVersion(KotlinTargetVersion.JAVA_6)
+ .build());
}
- public KotlinLambdaMergingDebugTest(TestParameters parameters, KotlinCompiler kotlinc) {
- super(KotlinTargetVersion.JAVA_6, kotlinc);
+ public KotlinLambdaMergingDebugTest(
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
new file mode 100644
index 0000000..a20a77d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingKeepAttributesKotlinStyleTest.java
@@ -0,0 +1,160 @@
+// Copyright (c) 2018, 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.kotlin.lambda;
+
+import static com.android.tools.r8.shaking.ProguardKeepAttributes.ENCLOSING_METHOD;
+import static com.android.tools.r8.shaking.ProguardKeepAttributes.INNER_CLASSES;
+import static com.android.tools.r8.shaking.ProguardKeepAttributes.SIGNATURE;
+import static junit.framework.TestCase.assertEquals;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KotlinLambdaMergingKeepAttributesKotlinStyleTest extends KotlinTestBase {
+
+ private final boolean allowAccessModification;
+ private final List<String> attributes;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}, {1}, allow access modification: {2}, attributes: {3}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters()
+ .withCfRuntime(CfVm.last())
+ .withDexRuntime(Version.last())
+ .withAllApiLevels()
+ .build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values(),
+ ImmutableList.of(
+ Collections.emptyList(),
+ ImmutableList.of(ENCLOSING_METHOD, INNER_CLASSES),
+ ImmutableList.of(ENCLOSING_METHOD, INNER_CLASSES, SIGNATURE)));
+ }
+
+ public KotlinLambdaMergingKeepAttributesKotlinStyleTest(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean allowAccessModification,
+ List<String> attributes) {
+ super(kotlinParameters);
+ this.allowAccessModification = allowAccessModification;
+ this.attributes = attributes;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testJVM() throws Exception {
+ assumeFalse(allowAccessModification);
+ assumeTrue(parameters.isCfRuntime());
+ assumeTrue(kotlinParameters.isFirst());
+ testForJvm()
+ .addProgramFiles(getProgramFiles())
+ .run(parameters.getRuntime(), getMainClassName())
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramFiles(getProgramFiles())
+ .addKeepMainRule(getMainClassName())
+ .applyIf(!attributes.isEmpty(), builder -> builder.addKeepAttributes(attributes))
+ .addDontWarnJetBrainsAnnotations()
+ .addHorizontallyMergedClassesInspector(this::inspect)
+ .allowAccessModification(allowAccessModification)
+ .allowDiagnosticWarningMessages()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .assertAllWarningMessagesMatch(
+ containsString("Resource 'META-INF/MANIFEST.MF' already exists."))
+ .run(parameters.getRuntime(), getMainClassName())
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+
+ private void inspect(HorizontallyMergedClassesInspector inspector) throws IOException {
+ // Get the Kotlin lambdas in the input.
+ KotlinLambdasInInput lambdasInInput =
+ KotlinLambdasInInput.create(getProgramFiles(), getTestName());
+ assertEquals(0, lambdasInInput.getNumberOfJStyleLambdas());
+ assertEquals(24, lambdasInInput.getNumberOfKStyleLambdas());
+
+ // All K-style Kotlin lambdas are merged if no attributes are kept.
+ if (attributes.isEmpty()) {
+ inspector.assertClassReferencesMerged(lambdasInInput.getKStyleLambdas());
+ } else {
+ // TODO(b/179018501): allow merging classes with inner/outer classes.
+ inspector.assertClassReferencesNotMerged(lambdasInInput.getKStyleLambdas());
+ }
+ }
+
+ private String getExpectedOutput() {
+ return StringUtils.lines(
+ "Alpha(id=11)",
+ "Beta(id=12)",
+ "Gamma(payload={any}, id=13)",
+ "Alpha(id=14)",
+ "First-1-Beta(id=15)",
+ "First-2-Beta(id=16)",
+ "First-3-Beta(id=17)",
+ "First-A-Gamma(payload=18, id=19)-11",
+ "First-B-Gamma(payload=20, id=21)-11",
+ "First-C-Gamma(payload=22, id=23)-11",
+ "First-D-Gamma(payload=24, id=25)-11",
+ "First-E-Gamma(payload=26, id=27)-11",
+ "First-F-Gamma(payload=28, id=29)-11",
+ "Second-1-Beta(id=30)",
+ "Second-2-Beta(id=31)",
+ "Second-3-Beta(id=32)",
+ "Second-A-Gamma(payload=33, id=34)-22",
+ "Second-B-Gamma(payload=35, id=36)-22",
+ "Second-C-Gamma(payload=37, id=38)-22",
+ "Second-D-Gamma(payload=39, id=40)-22",
+ "Second-E-Gamma(payload=41, id=42)-22",
+ "Second-F-Gamma(payload=43, id=44)-22",
+ "4321 45 46 47",
+ "1234 Alpha(id=48) Beta(id=49) Gamma(payload=50, id=51)");
+ }
+
+ private Path getJavaJarFile() {
+ return getJavaJarFile(getTestName());
+ }
+
+ private String getMainClassName() {
+ return getTestName() + ".MainKt";
+ }
+
+ private List<Path> getProgramFiles() {
+ Path kotlinJarFile =
+ getCompileMemoizer(getKotlinFilesInResource(getTestName()), getTestName())
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect())
+ .getForConfiguration(kotlinc, targetVersion);
+ return ImmutableList.of(kotlinJarFile, getJavaJarFile());
+ }
+
+ private String getTestName() {
+ return "lambdas_kstyle_generics";
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java
new file mode 100644
index 0000000..72abfe3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingSingletonTest.java
@@ -0,0 +1,155 @@
+// Copyright (c) 2018, 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.kotlin.lambda;
+
+import static com.android.tools.r8.utils.PredicateUtils.not;
+import static junit.framework.TestCase.assertEquals;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KotlinLambdaMergingSingletonTest extends KotlinTestBase {
+
+ private final boolean allowAccessModification;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}, {1}, allow access modification: {2}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters()
+ .withCfRuntime(CfVm.last())
+ .withDexRuntime(Version.last())
+ .withAllApiLevels()
+ .build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
+ }
+
+ public KotlinLambdaMergingSingletonTest(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean allowAccessModification) {
+ super(kotlinParameters);
+ this.allowAccessModification = allowAccessModification;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testJVM() throws Exception {
+ assumeFalse(allowAccessModification);
+ assumeTrue(parameters.isCfRuntime());
+ assumeTrue(kotlinParameters.isFirst());
+ testForJvm()
+ .addProgramFiles(getProgramFiles())
+ .run(parameters.getRuntime(), getMainClassName())
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramFiles(getProgramFiles())
+ .addKeepMainRule(getMainClassName())
+ .addDontWarnJetBrainsAnnotations()
+ .addHorizontallyMergedClassesInspector(this::inspect)
+ .allowAccessModification(allowAccessModification)
+ .allowDiagnosticWarningMessages()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .assertAllWarningMessagesMatch(
+ containsString("Resource 'META-INF/MANIFEST.MF' already exists."))
+ .run(parameters.getRuntime(), getMainClassName())
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+
+ private void inspect(HorizontallyMergedClassesInspector inspector) throws IOException {
+ // Get the Kotlin lambdas in the input.
+ KotlinLambdasInInput lambdasInInput =
+ KotlinLambdasInInput.create(getProgramFiles(), getTestName());
+ assertEquals(2, lambdasInInput.getNumberOfJStyleLambdas());
+ assertEquals(7, lambdasInInput.getNumberOfKStyleLambdas());
+
+ // All J-style Kotlin lambdas should be merged into one class.
+ inspector.assertIsCompleteMergeGroup(lambdasInInput.getJStyleLambdas());
+
+ // A subset of the K-style Kotlin lambdas should be merged into one class.
+ Set<ClassReference> kStyleLambdaMergeGroup =
+ Sets.newHashSet(
+ lambdasInInput.getKStyleLambdaReferenceFromTypeName(
+ getTestName(), "MainKt$test2$$inlined$process$1"),
+ lambdasInInput.getKStyleLambdaReferenceFromTypeName(
+ getTestName(), "MainKt$test2$$inlined$process$2"),
+ lambdasInInput.getKStyleLambdaReferenceFromTypeName(
+ getTestName(), "MainKt$test2$$inlined$process$3"),
+ lambdasInInput.getKStyleLambdaReferenceFromTypeName(
+ getTestName(), "MainKt$test2$$inlined$process$4"));
+ if (allowAccessModification) {
+ kStyleLambdaMergeGroup.add(
+ lambdasInInput.getKStyleLambdaReferenceFromTypeName(
+ getTestName(), "MainKt$test2$lambda$1"));
+ }
+ inspector.assertIsCompleteMergeGroup(kStyleLambdaMergeGroup);
+
+ // The remaining lambdas are not merged.
+ inspector.assertClassReferencesNotMerged(
+ lambdasInInput.getAllLambdas().stream()
+ .filter(not(lambdasInInput::isJStyleLambda))
+ .filter(not(kStyleLambdaMergeGroup::contains))
+ .collect(Collectors.toSet()));
+ }
+
+ private String getExpectedOutput() {
+ return StringUtils.lines(
+ "(*000*001*002*003*004*005*006*007*008*009*)",
+ "(*000*001*002*003*004*005*006*007*008*009*)",
+ "(*010*011*)",
+ "(*012*013*014*)",
+ "(*015*016*)",
+ "(*017*018*019*)");
+ }
+
+ private Path getJavaJarFile() {
+ return getJavaJarFile(getTestName());
+ }
+
+ private String getMainClassName() {
+ return getTestName() + ".MainKt";
+ }
+
+ private List<Path> getProgramFiles() {
+ Path kotlinJarFile =
+ getCompileMemoizer(getKotlinFilesInResource(getTestName()), getTestName())
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect())
+ .getForConfiguration(kotlinc, targetVersion);
+ return ImmutableList.of(kotlinJarFile, getJavaJarFile());
+ }
+
+ private String getTestName() {
+ return "lambdas_singleton";
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTest.java
deleted file mode 100644
index 4997fe3..0000000
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTest.java
+++ /dev/null
@@ -1,580 +0,0 @@
-// Copyright (c) 2018, 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.kotlin.lambda;
-
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-import static com.google.common.base.Predicates.alwaysTrue;
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertTrue;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.lambda.CaptureSignature;
-import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
-import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.google.common.collect.Lists;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public class KotlinLambdaMergingTest extends AbstractR8KotlinTestBase {
- private static final String KOTLIN_FUNCTION_IFACE = "Lkotlin/jvm/functions/Function";
- private static final String KOTLIN_FUNCTION_IFACE_STR = "kotlin.jvm.functions.Function";
-
- private void configure(InternalOptions options) {
- options.enableClassInlining = false;
- // The test checks that the generated lambdas inherit from Function, which is not true if
- // the unused interface removal is enabled.
- options.enableUnusedInterfaceRemoval = enableUnusedInterfaceRemoval;
- // Ensure that enclosing method and inner class attributes are kept even on classes that are
- // not explicitly mentioned by a keep rule.
- options.forceProguardCompatibility = true;
- options.horizontalClassMergerOptions().disableKotlinLambdaMerging();
- }
-
- private final boolean enableUnusedInterfaceRemoval;
-
- @Parameterized.Parameters(
- name =
- "target: {0}, kotlinc: {1}, allow access modification: {2}, unused interface removal:"
- + " {3}")
- public static Collection<Object[]> data() {
- return buildParameters(
- KotlinTargetVersion.values(),
- getKotlinCompilers(),
- BooleanUtils.values(),
- BooleanUtils.values());
- }
-
- public KotlinLambdaMergingTest(
- KotlinTargetVersion targetVersion,
- KotlinCompiler kotlinc,
- boolean allowAccessModification,
- boolean enableUnusedInterfaceRemoval) {
- super(targetVersion, kotlinc, allowAccessModification);
- this.enableUnusedInterfaceRemoval = enableUnusedInterfaceRemoval;
- }
-
- abstract static class LambdaOrGroup {
- abstract boolean match(DexClass clazz);
- }
-
- static class Group extends LambdaOrGroup {
- final String pkg;
- final String capture;
- final int arity;
- final String sam;
- final int singletons;
-
- private Group(String pkg, String capture, int arity, String sam, int singletons) {
- this.pkg = pkg;
- this.capture = fixCapture(capture);
- this.arity = arity;
- this.sam = sam;
- this.singletons = singletons;
- }
-
- private String fixCapture(String capture) {
- capture += "I";
- char[] chars = capture.toCharArray();
- Arrays.sort(chars);
- return new String(chars);
- }
-
- @Override
- public String toString() {
- return "group class " +
- (pkg.length() == 0 ? "" : pkg + "/") +
- "-$$LambdaGroup$XXXX (arity: " + arity +
- ", capture: " + capture + ", iface: " + sam + ", sing: " + singletons + ")";
- }
-
- @Override
- boolean match(DexClass clazz) {
- return clazz.type.getPackageDescriptor().equals(pkg) &&
- getLambdaOrGroupCapture(clazz).equals(capture) &&
- getLambdaSam(clazz).equals(sam) &&
- getLambdaSingletons(clazz) == singletons &&
- getLambdaOrGroupArity(clazz) == arity;
- }
- }
-
- private static Group kstyleImpl(String pkg, String capture, int arity, int singletons) {
- return new Group(pkg, capture, arity, KOTLIN_FUNCTION_IFACE_STR + arity, singletons);
- }
-
- static Group kstyle(String pkg, int arity) {
- return kstyleImpl(pkg, "", arity, 0);
- }
-
- static Group kstyle(String pkg, int arity, int singletons) {
- assertTrue(singletons != 0);
- return kstyleImpl(pkg, "", arity, singletons);
- }
-
- private static Group kstyle(String pkg, String capture, int arity) {
- assertFalse(capture.isEmpty());
- return kstyleImpl(pkg, capture, arity, 0);
- }
-
- private static Group jstyleImpl(
- String pkg, String capture, int arity, String sam, int singletons) {
- assertTrue(capture.isEmpty() || singletons == 0);
- return new Group(pkg, capture, arity, sam, singletons);
- }
-
- private static Group jstyle(String pkg, String capture, int arity, String sam) {
- return jstyleImpl(pkg, capture, arity, sam, 0);
- }
-
- private static Group jstyle(String pkg, int arity, String sam, int singletons) {
- return jstyleImpl(pkg, "", arity, sam, singletons);
- }
-
- static class Lambda extends LambdaOrGroup {
- final String pkg;
- final String name;
- final int arity;
-
- Lambda(String pkg, String name, int arity) {
- this.pkg = pkg;
- this.name = name;
- this.arity = arity;
- }
-
- @Override
- public String toString() {
- return "lambda class " +
- (pkg.length() == 0 ? "" : pkg + "/") +
- name + " (arity: " + arity + ")";
- }
-
- @Override
- boolean match(DexClass clazz) {
- return clazz.type.getPackageDescriptor().equals(pkg) &&
- clazz.type.getName().equals(name) &&
- getLambdaOrGroupArity(clazz) == arity;
- }
- }
-
- static class Verifier {
- final CodeInspector codeInspector;
- final List<DexClass> lambdas = new ArrayList<>();
- final List<DexClass> groups = new ArrayList<>();
-
- Verifier(CodeInspector codeInspector) {
- this.codeInspector = codeInspector;
- initGroupsAndLambdas();
- }
-
- private void initGroupsAndLambdas() {
- codeInspector.forAllClasses(
- clazz -> {
- DexClass dexClass = clazz.getDexProgramClass();
- if (isLambdaOrGroup(dexClass)) {
- if (isLambdaGroupClass(dexClass)) {
- groups.add(dexClass);
- } else {
- lambdas.add(dexClass);
- }
- }
- });
- }
-
- void assertLambdaGroups(Group... groups) {
- assertLambdasOrGroups("Lambda group", this.groups, groups);
- }
-
- void assertLambdas(Lambda... lambdas) {
- assertLambdasOrGroups("Lambda", this.lambdas, lambdas);
- }
-
- @SafeVarargs
- private static <T extends LambdaOrGroup>
- void assertLambdasOrGroups(String what, List<DexClass> objects, T... checks) {
- ArrayList<DexClass> list = Lists.newArrayList(objects);
- for (int i = 0; i < checks.length; i++) {
- T check = checks[i];
- for (DexClass clazz : list) {
- if (check.match(clazz)) {
- // Validate static initializer.
- if (check instanceof Group) {
- assertEquals(
- clazz.getMethodCollection().numberOfDirectMethods(),
- ((Group) check).singletons == 0 ? 1 : 2);
- }
-
- list.remove(clazz);
- checks[i] = null;
- break;
- }
- }
- }
-
- int notFound = 0;
- for (T check : checks) {
- if (check != null) {
- System.err.println(what + " not found: " + check);
- notFound++;
- }
- }
-
- for (DexClass dexClass : list) {
- System.err.println(what + " unexpected: " +
- dexClass.type.descriptor.toString() +
- ", arity: " + getLambdaOrGroupArity(dexClass) +
- ", capture: " + getLambdaOrGroupCapture(dexClass) +
- ", sam: " + getLambdaSam(dexClass) +
- ", sing: " + getLambdaSingletons(dexClass));
- notFound++;
- }
-
- assertTrue(what + "s match failed", 0 == notFound && 0 == list.size());
- }
- }
-
- private static int getLambdaOrGroupArity(DexClass clazz) {
- if (isKStyleLambdaOrGroup(clazz)) {
- for (DexType iface : clazz.interfaces.values) {
- String descr = iface.descriptor.toString();
- if (descr.startsWith(KOTLIN_FUNCTION_IFACE)) {
- return Integer.parseInt(
- descr.substring(KOTLIN_FUNCTION_IFACE.length(), descr.length() - 1));
- }
- }
-
- } else {
- assertTrue(isJStyleLambdaOrGroup(clazz));
- // Taking the number of any virtual method parameters seems to be good enough.
- assertTrue(clazz.getMethodCollection().hasVirtualMethods());
- return clazz.lookupVirtualMethod(alwaysTrue()).method.proto.parameters.size();
- }
- fail("Failed to get arity for " + clazz.type.descriptor.toString());
- throw new AssertionError();
- }
-
- private static String getLambdaSam(DexClass clazz) {
- assertEquals(1, clazz.interfaces.size());
- return clazz.interfaces.values[0].toSourceString();
- }
-
- private static int getLambdaSingletons(DexClass clazz) {
- assertEquals(1, clazz.interfaces.size());
- return clazz.staticFields().size();
- }
-
- private static boolean isLambdaOrGroup(DexClass clazz) {
- return !clazz.type.getPackageDescriptor().startsWith("kotlin") &&
- (isKStyleLambdaOrGroup(clazz) || isJStyleLambdaOrGroup(clazz));
- }
-
- private static boolean isKStyleLambdaOrGroup(DexClass clazz) {
- return clazz.superType.descriptor.toString().equals("Lkotlin/jvm/internal/Lambda;");
- }
-
- private static boolean isJStyleLambdaOrGroup(DexClass clazz) {
- return clazz.superType.descriptor.toString().equals("Ljava/lang/Object;") &&
- clazz.interfaces.size() == 1;
- }
-
- private static boolean isLambdaGroupClass(DexClass clazz) {
- return clazz.type.getName().startsWith("-$$LambdaGroup$");
- }
-
- private static String getLambdaOrGroupCapture(DexClass clazz) {
- return CaptureSignature.getCaptureSignature(clazz.instanceFields());
- }
-
- @Test
- public void testTrivialKs() throws Exception {
- final String mainClassName = "lambdas_kstyle_trivial.MainKt";
- runTest(
- "lambdas_kstyle_trivial",
- mainClassName,
- testBuilder ->
- testBuilder
- .addKeepRules(
- "-keepunusedarguments class * extends kotlin.jvm.internal.Lambda {"
- + " invoke(int, short); }")
- .addDontWarnJetBrainsNotNullAnnotation()
- .addOptionsModification(this::configure))
- .inspect(
- inspector -> {
- if (enableUnusedInterfaceRemoval) {
- // Only test that the code generates the same output as the input code does on the
- // JVM.
- return;
- }
-
- Verifier verifier = new Verifier(inspector);
- String pkg = "lambdas_kstyle_trivial";
-
- verifier.assertLambdaGroups(
- allowAccessModification
- ? new Group[] {
- kstyle("", 0, 4),
- kstyle("", 1, 9),
- kstyle("", 2, 2), // -\
- kstyle("", 2, 5), // - 3 groups different by main method
- kstyle("", 2, 4), // -/
- kstyle("", 3, 2),
- kstyle("", 22, 2)
- }
- : new Group[] {
- kstyle(pkg, 0, 2),
- kstyle(pkg, 1, 5),
- kstyle(pkg, 2, 5), // - 2 groups different by main method
- kstyle(pkg, 2, 4), // -/
- kstyle(pkg, 3, 2),
- kstyle(pkg, 22, 2),
- kstyle(pkg + "/inner", 0, 2),
- kstyle(pkg + "/inner", 1, 4)
- });
-
- verifier.assertLambdas(
- allowAccessModification
- ? new Lambda[] {}
- : new Lambda[] {
- new Lambda(pkg, "MainKt$testStateless$8", 2),
- new Lambda(pkg + "/inner", "InnerKt$testInnerStateless$7", 2)
- });
- });
- }
-
- @Test
- public void testCapturesKs() throws Exception {
- final String mainClassName = "lambdas_kstyle_captures.MainKt";
- runTest(
- "lambdas_kstyle_captures",
- mainClassName,
- testBuilder ->
- testBuilder
- .addDontWarnJetBrainsAnnotations()
- .addOptionsModification(this::configure))
- .inspect(
- inspector -> {
- if (enableUnusedInterfaceRemoval) {
- // Only test that the code generates the same output as the input code does on the
- // JVM.
- return;
- }
-
- Verifier verifier = new Verifier(inspector);
- String pkg = "lambdas_kstyle_captures";
- String grpPkg = allowAccessModification ? "" : pkg;
-
- verifier.assertLambdaGroups(
- kstyle(grpPkg, "LLL", 0),
- kstyle(grpPkg, "ILL", 0),
- kstyle(grpPkg, "III", 0),
- kstyle(grpPkg, "BCDFIJLLLLSZ", 0),
- kstyle(grpPkg, "BCDFIJLLSZ", 0));
-
- verifier.assertLambdas(
- new Lambda(pkg, "MainKt$test1$15", 0),
- new Lambda(pkg, "MainKt$test2$10", 0),
- new Lambda(pkg, "MainKt$test2$11", 0),
- new Lambda(pkg, "MainKt$test2$9", 0));
- });
- }
-
- @Test
- public void testGenericsNoSignatureKs() throws Exception {
- final String mainClassName = "lambdas_kstyle_generics.MainKt";
- runTest(
- "lambdas_kstyle_generics",
- mainClassName,
- testBuilder ->
- testBuilder
- .addDontWarnJetBrainsAnnotations()
- .addOptionsModification(this::configure))
- .inspect(
- inspector -> {
- if (enableUnusedInterfaceRemoval) {
- // Only test that the code generates the same output as the input code does on the
- // JVM.
- return;
- }
-
- Verifier verifier = new Verifier(inspector);
- String pkg = "lambdas_kstyle_generics";
- String grpPkg = allowAccessModification ? "" : pkg;
-
- verifier.assertLambdaGroups(
- kstyle(grpPkg, 1, 3), // Group for Any
- kstyle(grpPkg, "L", 1), // Group for Beta
- kstyle(grpPkg, "LS", 1), // Group for Gamma
- kstyle(grpPkg, 1, 2) // Group for int
- );
-
- verifier.assertLambdas(new Lambda(pkg, "MainKt$main$4", 1));
- });
- }
-
- @Test
- public void testInnerClassesAndEnclosingMethodsKs() throws Exception {
- final String mainClassName = "lambdas_kstyle_generics.MainKt";
- runTest(
- "lambdas_kstyle_generics",
- mainClassName,
- testBuilder ->
- testBuilder
- .addDontWarnJetBrainsAnnotations()
- .addKeepAttributeInnerClassesAndEnclosingMethod()
- .addOptionsModification(this::configure))
- .inspect(
- inspector -> {
- if (enableUnusedInterfaceRemoval) {
- // Only test that the code generates the same output as the input code does on the
- // JVM.
- return;
- }
-
- Verifier verifier = new Verifier(inspector);
- String pkg = "lambdas_kstyle_generics";
- String grpPkg = allowAccessModification ? "" : pkg;
-
- verifier.assertLambdaGroups(
- kstyle(grpPkg, 1, 3), // Group for Any
- kstyle(grpPkg, "L", 1), // Group for Beta // First
- kstyle(grpPkg, "L", 1), // Group for Beta // Second
- kstyle(grpPkg, "LS", 1), // Group for Gamma // First
- kstyle(grpPkg, "LS", 1), // Group for Gamma // Second
- kstyle(grpPkg, 1, 2) // Group for int
- );
-
- verifier.assertLambdas(new Lambda(pkg, "MainKt$main$4", 1));
- });
- }
-
- @Test
- public void testGenericsSignatureInnerEnclosingKs() throws Exception {
- final String mainClassName = "lambdas_kstyle_generics.MainKt";
- runTest(
- "lambdas_kstyle_generics",
- mainClassName,
- // KEEP_SIGNATURE_INNER_ENCLOSING,
- testBuilder ->
- testBuilder
- .addDontWarnJetBrainsAnnotations()
- .addKeepAttributeInnerClassesAndEnclosingMethod()
- .addKeepAttributeSignature()
- .addOptionsModification(this::configure))
- .inspect(
- inspector -> {
- if (enableUnusedInterfaceRemoval) {
- // Only test that the code generates the same output as the input code does on the
- // JVM.
- return;
- }
-
- Verifier verifier = new Verifier(inspector);
- String pkg = "lambdas_kstyle_generics";
- String grpPkg = allowAccessModification ? "" : pkg;
-
- verifier.assertLambdaGroups(
- kstyle(grpPkg, 1, 3), // Group for Any
- kstyle(grpPkg, "L", 1), // Group for Beta in First
- kstyle(grpPkg, "L", 1), // Group for Beta in Second
- kstyle(grpPkg, "LS", 1), // Group for Gamma<String> in First
- kstyle(grpPkg, "LS", 1), // Group for Gamma<Integer> in First
- kstyle(grpPkg, "LS", 1), // Group for Gamma<String> in Second
- kstyle(grpPkg, "LS", 1), // Group for Gamma<Integer> in Second
- kstyle(grpPkg, 1, 2) // Group for int
- );
-
- verifier.assertLambdas(new Lambda(pkg, "MainKt$main$4", 1));
- });
- }
-
- @Test
- public void testTrivialJs() throws Exception {
- final String mainClassName = "lambdas_jstyle_trivial.MainKt";
- runTest(
- "lambdas_jstyle_trivial",
- mainClassName,
- testBuilder ->
- testBuilder
- .addDontWarnJetBrainsAnnotations()
- .addOptionsModification(this::configure))
- .inspect(
- inspector -> {
- Verifier verifier = new Verifier(inspector);
- String pkg = "lambdas_jstyle_trivial";
- String grp = allowAccessModification ? "" : pkg;
-
- String supplier = "lambdas_jstyle_trivial.Lambdas$Supplier";
- String intSupplier = "lambdas_jstyle_trivial.Lambdas$IntSupplier";
- String consumer = "lambdas_jstyle_trivial.Lambdas$Consumer";
- String intConsumer = "lambdas_jstyle_trivial.Lambdas$IntConsumer";
- String multiFunction = "lambdas_jstyle_trivial.Lambdas$MultiFunction";
-
- verifier.assertLambdaGroups(
- jstyle(grp, 0, intSupplier, 2),
- jstyle(grp, "L", 0, supplier),
- jstyle(grp, "LL", 0, supplier),
- jstyle(grp, "LLL", 0, supplier),
- jstyle(grp, 1, intConsumer, allowAccessModification ? 3 : 2),
- jstyle(grp, "I", 1, consumer),
- jstyle(grp, "II", 1, consumer),
- jstyle(grp, "III", 1, consumer),
- jstyle(grp, "IIII", 1, consumer),
- jstyle(grp, 3, multiFunction, 2),
- jstyle(grp, 3, multiFunction, 2),
- jstyle(grp, 3, multiFunction, 4),
- jstyle(grp, 3, multiFunction, 6));
-
- verifier.assertLambdas(
- allowAccessModification
- ? new Lambda[] {
- new Lambda(pkg + "/inner", "InnerKt$testInner1$4", 1),
- new Lambda(pkg + "/inner", "InnerKt$testInner1$5", 1)
- }
- : new Lambda[] {
- new Lambda(pkg + "/inner", "InnerKt$testInner1$1", 1),
- new Lambda(pkg + "/inner", "InnerKt$testInner1$2", 1),
- new Lambda(pkg + "/inner", "InnerKt$testInner1$3", 1),
- new Lambda(pkg + "/inner", "InnerKt$testInner1$4", 1),
- new Lambda(pkg + "/inner", "InnerKt$testInner1$5", 1)
- });
- });
- }
-
- @Test
- public void testSingleton() throws Exception {
- final String mainClassName = "lambdas_singleton.MainKt";
- runTest(
- "lambdas_singleton",
- mainClassName,
- testBuilder ->
- testBuilder
- .addDontWarnJetBrainsAnnotations()
- .addOptionsModification(this::configure)
- .noHorizontalClassMerging())
- .inspect(
- inspector -> {
- Verifier verifier = new Verifier(inspector);
- String pkg = "lambdas_singleton";
- String grp = allowAccessModification ? "" : pkg;
-
- verifier.assertLambdaGroups(
- kstyle(grp, 1 /* 1 out of 5 lambdas in the group */),
- jstyle(grp, 2, "java.util.Comparator", 0 /* 0 out of 2 lambdas in the group */));
-
- verifier.assertLambdas(/* None */ );
- });
- }
-}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java
new file mode 100644
index 0000000..1e83c00
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialJavaStyleTest.java
@@ -0,0 +1,210 @@
+// Copyright (c) 2018, 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.kotlin.lambda;
+
+import static com.android.tools.r8.utils.PredicateUtils.not;
+import static junit.framework.TestCase.assertEquals;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KotlinLambdaMergingTrivialJavaStyleTest extends KotlinTestBase {
+
+ private final boolean allowAccessModification;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}, {1}, allow access modification: {2}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters()
+ .withCfRuntime(CfVm.last())
+ .withDexRuntime(Version.last())
+ .withAllApiLevels()
+ .build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
+ }
+
+ public KotlinLambdaMergingTrivialJavaStyleTest(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean allowAccessModification) {
+ super(kotlinParameters);
+ this.allowAccessModification = allowAccessModification;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testJVM() throws Exception {
+ assumeFalse(allowAccessModification);
+ assumeTrue(parameters.isCfRuntime());
+ assumeTrue(kotlinParameters.isFirst());
+ testForJvm()
+ .addProgramFiles(getProgramFiles())
+ .run(parameters.getRuntime(), getMainClassName())
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramFiles(getProgramFiles())
+ .addKeepMainRule(getMainClassName())
+ .addDontWarnJetBrainsAnnotations()
+ .addHorizontallyMergedClassesInspector(this::inspect)
+ .allowAccessModification(allowAccessModification)
+ .allowDiagnosticWarningMessages()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .assertAllWarningMessagesMatch(
+ containsString("Resource 'META-INF/MANIFEST.MF' already exists."))
+ .run(parameters.getRuntime(), getMainClassName())
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+
+ private void inspect(HorizontallyMergedClassesInspector inspector) throws IOException {
+ // Get the Kotlin lambdas in the input.
+ KotlinLambdasInInput lambdasInInput =
+ KotlinLambdasInInput.create(getProgramFiles(), getTestName());
+ assertEquals(39, lambdasInInput.getNumberOfJStyleLambdas());
+ assertEquals(0, lambdasInInput.getNumberOfKStyleLambdas());
+
+ if (!allowAccessModification) {
+ // Only a subset of all J-style Kotlin lambdas are merged without -allowaccessmodification.
+ Set<ClassReference> unmergedLambdas =
+ ImmutableSet.of(
+ lambdasInInput.getJStyleLambdaReferenceFromTypeName(
+ getTestName(), "inner.InnerKt$testInner1$1"),
+ lambdasInInput.getJStyleLambdaReferenceFromTypeName(
+ getTestName(), "inner.InnerKt$testInner1$2"),
+ lambdasInInput.getJStyleLambdaReferenceFromTypeName(
+ getTestName(), "inner.InnerKt$testInner1$3"),
+ lambdasInInput.getJStyleLambdaReferenceFromTypeName(
+ getTestName(), "inner.InnerKt$testInner1$4"),
+ lambdasInInput.getJStyleLambdaReferenceFromTypeName(
+ getTestName(), "inner.InnerKt$testInner1$5"));
+ inspector
+ .assertClassReferencesMerged(
+ lambdasInInput.getJStyleLambdas().stream()
+ .filter(not(unmergedLambdas::contains))
+ .collect(Collectors.toList()))
+ .assertClassReferencesNotMerged(unmergedLambdas);
+ return;
+ }
+
+ // All J-style Kotlin lambdas are merged with -allowaccessmodification.
+ inspector.assertClassReferencesMerged(lambdasInInput.getJStyleLambdas());
+ }
+
+ private String getExpectedOutput() {
+ return StringUtils.lines(
+ "{005:4}",
+ "{007:6}",
+ "009:{008}:{0}",
+ "011:{010}:{0}",
+ "013:{012}:{0}:{1}",
+ "015:{014}:{0}:{1}",
+ "017:{Local(id=016)}:{0}:{1}:{2}",
+ "019:{Local(id=018)}:{0}:{1}:{2}",
+ "021:{Local(id=Local(id=020))}:{0}:{1}:{2}:{3}",
+ "023:{Local(id=Local(id=022))}:{0}:{1}:{2}:{3}",
+ "27",
+ "kotlin.Unit",
+ "28",
+ "kotlin.Unit",
+ "029:024",
+ "kotlin.Unit",
+ "030:024",
+ "kotlin.Unit",
+ "031:024",
+ "kotlin.Unit",
+ "032:024",
+ "kotlin.Unit",
+ "Local(id=033):024:025",
+ "kotlin.Unit",
+ "Local(id=034):024:025",
+ "kotlin.Unit",
+ "Local(id=Local(id=035)):024:025:026",
+ "kotlin.Unit",
+ "Local(id=Local(id=036)):024:025:026",
+ "kotlin.Unit",
+ "037:038:039",
+ "039:037:038",
+ "038:039:037",
+ "Local(id=037):038:039",
+ "Local(id=038):037:039",
+ "037:Local(id=038):039",
+ "037:Local(id=039):038",
+ "Local(id=Local(id=037)):Local(id=Local(id=038)):Local(id=Local(id=039))",
+ "Local(id=Local(id=039)):Local(id=Local(id=037)):Local(id=Local(id=038))",
+ "040:Local(id=041):Local(id=Local(id=042))",
+ "Local(id=Local(id=042)):040:Local(id=041)",
+ "Local(id=041):Local(id=Local(id=042)):040",
+ "Local(id=040):Local(id=041):Local(id=Local(id=042))",
+ "Local(id=Local(id=041)):040:Local(id=Local(id=042))",
+ "040:Local(id=Local(id=041)):Local(id=Local(id=042))",
+ "040:Local(id=Local(id=Local(id=042))):Local(id=041)",
+ "Local(id=Local(id=040)):Local(id=Local(id=Local(id=041))):Local(id=Local(id=Local(id=Local(id=042))))",
+ "Local(id=Local(id=Local(id=Local(id=042)))):Local(id=Local(id=040)):Local(id=Local(id=Local(id=041)))",
+ "043:044:045",
+ "045:043:044",
+ "044:045:043",
+ "Local(id=043):044:045",
+ "Local(id=044):043:045",
+ "046:Local(id=047):Local(id=048)",
+ "Local(id=048):046:Local(id=047)",
+ "Local(id=047):Local(id=048):046",
+ "Local(id=046):Local(id=047):Local(id=048)",
+ "Local(id=Local(id=047)):046:Local(id=048)",
+ "{053:100}",
+ "055:{054}:{49}",
+ "057:{056}:{49}:{50}",
+ "059:{InnerLocal(id=058)}:{49}:{50}:{51}",
+ "061:{InnerLocal(id=InnerLocal(id=060))}:{49}:{50}:{51}:{52");
+ }
+
+ private Path getJavaJarFile() {
+ return getJavaJarFile(getTestName());
+ }
+
+ private String getMainClassName() {
+ return getTestName() + ".MainKt";
+ }
+
+ private List<Path> getProgramFiles() {
+ Path kotlinJarFile =
+ getCompileMemoizer(getKotlinFilesInResource(getTestName()), getTestName())
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect())
+ .getForConfiguration(kotlinc, targetVersion);
+ return ImmutableList.of(kotlinJarFile, getJavaJarFile());
+ }
+
+ private String getTestName() {
+ return "lambdas_jstyle_trivial";
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
new file mode 100644
index 0000000..3515109
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTrivialKotlinStyleTest.java
@@ -0,0 +1,171 @@
+// Copyright (c) 2018, 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.kotlin.lambda;
+
+import static com.android.tools.r8.utils.PredicateUtils.not;
+import static junit.framework.TestCase.assertEquals;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KotlinLambdaMergingTrivialKotlinStyleTest extends KotlinTestBase {
+
+ private final boolean allowAccessModification;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}, {1}, allow access modification: {2}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters()
+ .withCfRuntime(CfVm.last())
+ .withDexRuntime(Version.last())
+ .withAllApiLevels()
+ .build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
+ }
+
+ public KotlinLambdaMergingTrivialKotlinStyleTest(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean allowAccessModification) {
+ super(kotlinParameters);
+ this.allowAccessModification = allowAccessModification;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testJVM() throws Exception {
+ assumeFalse(allowAccessModification);
+ assumeTrue(parameters.isCfRuntime());
+ assumeTrue(kotlinParameters.isFirst());
+ testForJvm()
+ .addProgramFiles(getProgramFiles())
+ .run(parameters.getRuntime(), getMainClassName())
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramFiles(getProgramFiles())
+ .addKeepMainRule(getMainClassName())
+ .addDontWarnJetBrainsNotNullAnnotation()
+ .addHorizontallyMergedClassesInspector(this::inspect)
+ .allowAccessModification(allowAccessModification)
+ .allowDiagnosticWarningMessages()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .assertAllWarningMessagesMatch(
+ containsString("Resource 'META-INF/MANIFEST.MF' already exists."))
+ .run(parameters.getRuntime(), getMainClassName())
+ .assertSuccessWithOutput(getExpectedOutput());
+ }
+
+ private void inspect(HorizontallyMergedClassesInspector inspector) throws IOException {
+ // Get the Kotlin lambdas in the input.
+ KotlinLambdasInInput lambdasInInput =
+ KotlinLambdasInInput.create(getProgramFiles(), getTestName());
+ assertEquals(0, lambdasInInput.getNumberOfJStyleLambdas());
+ assertEquals(28, lambdasInInput.getNumberOfKStyleLambdas());
+
+ if (!allowAccessModification) {
+ // Only a subset of all K-style Kotlin lambdas are merged without -allowaccessmodification.
+ Set<ClassReference> unmergedLambdas =
+ ImmutableSet.of(
+ lambdasInInput.getKStyleLambdaReferenceFromTypeName(
+ getTestName(), "inner.InnerKt$testInnerStateless$7"));
+ inspector
+ .assertClassReferencesMerged(
+ lambdasInInput.getKStyleLambdas().stream()
+ .filter(not(unmergedLambdas::contains))
+ .collect(Collectors.toList()))
+ .assertClassReferencesNotMerged(unmergedLambdas);
+ return;
+ }
+
+ // All K-style Kotlin lambdas are merged with -allowaccessmodification.
+ inspector.assertClassReferencesMerged(lambdasInInput.getKStyleLambdas());
+ }
+
+ private String getExpectedOutput() {
+ return StringUtils.lines(
+ "first empty",
+ "second empty",
+ "first single",
+ "second single",
+ "third single",
+ "caught: exception#14",
+ "15",
+ "16-17",
+ "181920",
+ "one-two-three",
+ "one-two-...-twentythree",
+ "46474849505152535455565758596061626364656667",
+ "first empty",
+ "second empty",
+ "first single",
+ "second single",
+ "third single",
+ "71",
+ "72-73",
+ "1",
+ "5",
+ "8",
+ "20",
+ "5",
+ "",
+ "kotlin.Unit",
+ "10",
+ "kotlin.Unit",
+ "13",
+ "kotlin.Unit",
+ "14 -- 10",
+ "kotlin.Unit");
+ }
+
+ private Path getJavaJarFile() {
+ return getJavaJarFile(getTestName());
+ }
+
+ private String getMainClassName() {
+ return getTestName() + ".MainKt";
+ }
+
+ private List<Path> getProgramFiles() {
+ Path kotlinJarFile =
+ getCompileMemoizer(getKotlinFilesInResource(getTestName()), getTestName())
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect())
+ .getForConfiguration(kotlinc, targetVersion);
+ return ImmutableList.of(kotlinJarFile, getJavaJarFile());
+ }
+
+ private String getTestName() {
+ return "lambdas_kstyle_trivial";
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithReprocessingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithReprocessingTest.java
index b8fb366..8258582 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithReprocessingTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithReprocessingTest.java
@@ -3,10 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.lambda;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestShrinkerBuilder;
import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
import com.android.tools.r8.utils.BooleanUtils;
import java.util.Collection;
@@ -17,15 +15,16 @@
@RunWith(Parameterized.class)
public class KotlinLambdaMergingWithReprocessingTest extends AbstractR8KotlinTestBase {
- @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
+ @Parameterized.Parameters(name = "{0}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
}
public KotlinLambdaMergingWithReprocessingTest(
- KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ KotlinTestParameters kotlinParameters, boolean allowAccessModification) {
+ super(kotlinParameters, allowAccessModification);
}
@Test
@@ -34,14 +33,6 @@
runTest(
"reprocess_merged_lambdas_kstyle",
mainClassName,
- testBuilder ->
- testBuilder
- .addDontWarnJetBrainsNotNullAnnotation()
- .addOptionsModification(
- options -> {
- options.enableInlining = true;
- options.enableClassInlining = true;
- options.enableLambdaMerging = true;
- }));
+ TestShrinkerBuilder::addDontWarnJetBrainsNotNullAnnotation);
}
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithSmallInliningBudgetTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithSmallInliningBudgetTest.java
index 5032ea2..087a81b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithSmallInliningBudgetTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithSmallInliningBudgetTest.java
@@ -3,10 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.lambda;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
import com.android.tools.r8.utils.BooleanUtils;
import java.util.Collection;
@@ -17,15 +14,16 @@
@RunWith(Parameterized.class)
public class KotlinLambdaMergingWithSmallInliningBudgetTest extends AbstractR8KotlinTestBase {
- @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
+ @Parameterized.Parameters(name = "{0}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values());
}
public KotlinLambdaMergingWithSmallInliningBudgetTest(
- KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
- super(targetVersion, kotlinc, allowAccessModification);
+ KotlinTestParameters kotlinParameters, boolean allowAccessModification) {
+ super(kotlinParameters, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdasInInput.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdasInInput.java
new file mode 100644
index 0000000..3517ff3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdasInInput.java
@@ -0,0 +1,125 @@
+// Copyright (c) 2021, 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.kotlin.lambda;
+
+import static junit.framework.TestCase.assertTrue;
+
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.SetUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class KotlinLambdasInInput {
+
+ private final Set<ClassReference> jStyleLambdas;
+ private final Set<ClassReference> kStyleLambdas;
+
+ private KotlinLambdasInInput(
+ Set<ClassReference> jStyleLambdas, Set<ClassReference> kStyleLambdas) {
+ this.jStyleLambdas = jStyleLambdas;
+ this.kStyleLambdas = kStyleLambdas;
+ }
+
+ public static KotlinLambdasInInput create(List<Path> programFiles, String testName)
+ throws IOException {
+ CodeInspector inputInspector = new CodeInspector(programFiles);
+ Set<ClassReference> jStyleLambdas = new HashSet<>();
+ Set<ClassReference> kStyleLambdas = new HashSet<>();
+ for (FoundClassSubject classSubject : inputInspector.allClasses()) {
+ DexProgramClass clazz = classSubject.getDexProgramClass();
+ if (!clazz.getType().getPackageName().startsWith(testName)) {
+ continue;
+ }
+ if (internalIsJStyleLambda(clazz)) {
+ jStyleLambdas.add(Reference.classFromTypeName(clazz.getTypeName()));
+ } else if (internalIsKStyleLambda(clazz)) {
+ kStyleLambdas.add(Reference.classFromTypeName(clazz.getTypeName()));
+ }
+ }
+ return new KotlinLambdasInInput(jStyleLambdas, kStyleLambdas);
+ }
+
+ private static boolean internalIsKStyleLambda(DexProgramClass clazz) {
+ return clazz.getSuperType().getTypeName().equals("kotlin.jvm.internal.Lambda");
+ }
+
+ private static boolean internalIsJStyleLambda(DexProgramClass clazz) {
+ if (!clazz.getSuperType().getTypeName().equals(Object.class.getTypeName())
+ || clazz.getInterfaces().size() != 1
+ || clazz.getMethodCollection().numberOfVirtualMethods() == 0) {
+ return false;
+ }
+ if (clazz
+ .getMethodCollection()
+ .hasDirectMethods(method -> method.isStatic() && !method.isClassInitializer())) {
+ return false;
+ }
+ int numberOfFinalNonBridgeNonSyntheticMethods = 0;
+ for (DexEncodedMethod method : clazz.virtualMethods()) {
+ if (method.isFinal() && !method.isBridge() && !method.isSyntheticMethod()) {
+ numberOfFinalNonBridgeNonSyntheticMethods++;
+ }
+ }
+ return numberOfFinalNonBridgeNonSyntheticMethods == 1;
+ }
+
+ public Set<ClassReference> getAllLambdas() {
+ return SetUtils.newIdentityHashSet(jStyleLambdas, kStyleLambdas);
+ }
+
+ public Set<ClassReference> getJStyleLambdas() {
+ return jStyleLambdas;
+ }
+
+ public ClassReference getJStyleLambdaReferenceFromTypeName(String testName, String simpleName) {
+ ClassReference classReference = Reference.classFromTypeName(testName + "." + simpleName);
+ assertTrue(jStyleLambdas.contains(classReference));
+ return classReference;
+ }
+
+ public Set<ClassReference> getKStyleLambdas() {
+ return kStyleLambdas;
+ }
+
+ public ClassReference getKStyleLambdaReferenceFromTypeName(String testName, String simpleName) {
+ ClassReference classReference = Reference.classFromTypeName(testName + "." + simpleName);
+ assertTrue(
+ "Class is not a Kotlin-style lambda: " + classReference.getTypeName(),
+ kStyleLambdas.contains(classReference));
+ return classReference;
+ }
+
+ public int getNumberOfJStyleLambdas() {
+ return jStyleLambdas.size();
+ }
+
+ public int getNumberOfKStyleLambdas() {
+ return kStyleLambdas.size();
+ }
+
+ public boolean isJStyleLambda(ClassReference classReference) {
+ return jStyleLambdas.contains(classReference);
+ }
+
+ public boolean isKStyleLambda(ClassReference classReference) {
+ return kStyleLambdas.contains(classReference);
+ }
+
+ public void print() {
+ System.out.println("Java-style Kotlin lambdas:");
+ jStyleLambdas.forEach(lambda -> System.out.println(lambda.getTypeName()));
+ System.out.println();
+ System.out.println("Kotlin-style Kotlin lambdas:");
+ kStyleLambdas.forEach(lambda -> System.out.println(lambda.getTypeName()));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinxMetadataExtensionsServiceTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinxMetadataExtensionsServiceTest.java
deleted file mode 100644
index 26cc829..0000000
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinxMetadataExtensionsServiceTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (c) 2018, 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.kotlin.lambda;
-
-import static com.android.tools.r8.ToolHelper.EXAMPLES_KOTLIN_RESOURCE_DIR;
-import static com.android.tools.r8.kotlin.lambda.KotlinLambdaMergingTest.kstyle;
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.kotlin.lambda.KotlinLambdaMergingTest.Group;
-import com.android.tools.r8.kotlin.lambda.KotlinLambdaMergingTest.Lambda;
-import com.android.tools.r8.kotlin.lambda.KotlinLambdaMergingTest.Verifier;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.FileUtils;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.google.common.collect.ImmutableList;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-import org.junit.Test;
-
-public class KotlinxMetadataExtensionsServiceTest extends TestBase {
-
- private void forkR8_kstyle_trivial(boolean allowAccessModification) throws Exception {
- if (!isRunR8Jar()) {
- return;
- }
- Path working = temp.getRoot().toPath();
- Path kotlinJar =
- Paths.get(EXAMPLES_KOTLIN_RESOURCE_DIR, "JAVA_8", "lambdas_kstyle_trivial.jar")
- .toAbsolutePath();
- Path output = working.resolve("classes.dex");
- assertFalse(Files.exists(output));
- Path proguardConfiguration = temp.newFile("test.conf").toPath();
- List<String> lines = ImmutableList.of(
- "-keepattributes Signature,InnerClasses,EnclosingMethod",
- "-keep class **MainKt {",
- " public static void main(...);",
- "}",
- "-printmapping",
- "-dontobfuscate",
- allowAccessModification ? "-allowaccessmodification" : ""
- );
- FileUtils.writeTextFile(proguardConfiguration, lines);
- ProcessResult result = ToolHelper.forkR8Jar(working,
- "--pg-conf", proguardConfiguration.toString(),
- "--lib", ToolHelper.getAndroidJar(AndroidApiLevel.O).toAbsolutePath().toString(),
- kotlinJar.toString());
- assertEquals(0, result.exitCode);
- assertThat(result.stderr, not(containsString(
- "No MetadataExtensions instances found in the classpath")));
- assertTrue(Files.exists(output));
-
- CodeInspector inspector = new CodeInspector(output);
- Verifier verifier = new Verifier(inspector);
- String pkg = "lambdas_kstyle_trivial";
- verifier.assertLambdaGroups(
- allowAccessModification
- ? new Group[] {
- kstyle("", 0, 4),
- kstyle("", 1, 9),
- kstyle("", 2, 2), // -\
- kstyle("", 2, 5), // - 3 groups different by main method
- kstyle("", 2, 4), // -/
- kstyle("", 3, 2),
- kstyle("", 22, 2)
- }
- : new Group[] {
- kstyle(pkg, 0, 2),
- kstyle(pkg, 1, 5),
- kstyle(pkg, 2, 5), // - 2 groups different by main method
- kstyle(pkg, 2, 4), // -/
- kstyle(pkg, 3, 2),
- kstyle(pkg, 22, 2),
- kstyle(pkg + "/inner", 0, 2),
- kstyle(pkg + "/inner", 1, 4)
- });
-
- verifier.assertLambdas(
- allowAccessModification
- ? new Lambda[] {}
- : new Lambda[] {
- new Lambda(pkg, "MainKt$testStateless$8", 2),
- new Lambda(pkg + "/inner", "InnerKt$testInnerStateless$7", 2)
- });
- }
-
- @Test
- public void testTrivialKs_allowAccessModification() throws Exception {
- forkR8_kstyle_trivial(true);
- }
-
- @Test
- public void testTrivialKs_notAllowAccessModification() throws Exception {
- forkR8_kstyle_trivial(false);
- }
-
-}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java
index e9f4e46..ac22198 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java
@@ -4,31 +4,19 @@
package com.android.tools.r8.kotlin.lambda.b148525512;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.ArchiveResourceProvider;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
-import com.android.tools.r8.utils.codeinspector.InstructionSubject;
-import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.List;
-import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -57,17 +45,15 @@
});
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withDexRuntimes().withAllApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
- public B148525512(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ public B148525512(TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
@@ -84,35 +70,6 @@
}
}
- private void checkLambdaGroups(CodeInspector inspector) {
- List<FoundClassSubject> lambdaGroups =
- inspector.allClasses().stream()
- .filter(clazz -> clazz.getOriginalName().contains("LambdaGroup"))
- .collect(Collectors.toList());
- assertEquals(1, lambdaGroups.size());
- MethodSubject invokeMethod = lambdaGroups.get(0).uniqueMethodWithName("invoke");
- assertThat(invokeMethod, isPresent());
- // The lambda group has 2 captures which capture "Base".
- assertEquals(
- 2,
- invokeMethod
- .streamInstructions()
- .filter(InstructionSubject::isCheckCast)
- .filter(
- instruction ->
- instruction.asCheckCast().getType().toSourceString().contains("Base"))
- .count());
- // The lambda group has no captures which capture "Feature" (lambdas in the feature are not
- // in this lambda group).
- assertTrue(
- invokeMethod
- .streamInstructions()
- .filter(InstructionSubject::isCheckCast)
- .noneMatch(
- instruction ->
- instruction.asCheckCast().getType().toSourceString().contains("Feature")));
- }
-
@Test
public void test() throws Exception {
Path featureCode = temp.newFile("feature.zip").toPath();
@@ -125,10 +82,16 @@
.addKeepClassAndMembersRules(baseClassName)
.addKeepClassAndMembersRules(featureKtClassNamet)
.addKeepClassAndMembersRules(FeatureAPI.class)
- .addOptionsModification(
- options -> options.horizontalClassMergerOptions().disableKotlinLambdaMerging())
+ .addHorizontallyMergedClassesInspector(
+ inspector ->
+ inspector
+ .assertIsCompleteMergeGroup(
+ "com.android.tools.r8.kotlin.lambda.b148525512.BaseKt$main$1",
+ "com.android.tools.r8.kotlin.lambda.b148525512.BaseKt$main$2")
+ .assertIsCompleteMergeGroup(
+ "com.android.tools.r8.kotlin.lambda.b148525512.FeatureKt$feature$1",
+ "com.android.tools.r8.kotlin.lambda.b148525512.FeatureKt$feature$2"))
.setMinApi(parameters.getApiLevel())
- .noMinification() // The check cast inspection above relies on original names.
.addFeatureSplit(
builder ->
builder
@@ -142,10 +105,9 @@
.addDontWarnJetBrainsNotNullAnnotation()
.compile()
.assertAllWarningMessagesMatch(
- equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
- .inspect(this::checkLambdaGroups);
+ equalTo("Resource 'META-INF/MANIFEST.MF' already exists."));
- // Run the code without the feature code present.
+ // Run the code without the feature code.
compileResult
.run(parameters.getRuntime(), baseKtClassName)
.assertSuccessWithOutputLines("1", "2");
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
index c33d03b..8d476be 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
@@ -11,21 +11,19 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions.HorizontalClassMergerOptions;
-import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
-import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -34,36 +32,61 @@
@RunWith(Parameterized.class)
public class LambdaGroupGCLimitTest extends TestBase {
- private final boolean enableHorizontalClassMergingOfKotlinLambdas;
- private final TestParameters parameters;
- private final int LAMBDA_HOLDER_LIMIT = 50;
- private final int LAMBDAS_PER_CLASS_LIMIT = 100;
+ private static final int LAMBDA_HOLDER_LIMIT = 50;
+ private static final int LAMBDAS_PER_CLASS_LIMIT = 100;
- @Parameters(name = "{1}, horizontal class merging: {0}")
- public static List<Object[]> data() {
- return buildParameters(
- BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimes().withAllApiLevels().build();
}
- public LambdaGroupGCLimitTest(
- boolean enableHorizontalClassMergingOfKotlinLambdas, TestParameters parameters) {
- this.enableHorizontalClassMergingOfKotlinLambdas = enableHorizontalClassMergingOfKotlinLambdas;
+ public LambdaGroupGCLimitTest(TestParameters parameters) {
this.parameters = parameters;
}
@Test
public void testR8() throws ExecutionException, CompilationFailedException, IOException {
String PKG_NAME = LambdaGroupGCLimitTest.class.getPackage().getName();
- R8FullTestBuilder testBuilder =
+ R8TestCompileResult compileResult =
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar(ToolHelper.getKotlinC_1_3_72()))
- .addOptionsModification(
- options ->
- options
- .horizontalClassMergerOptions()
- .enableKotlinLambdaMergingIf(enableHorizontalClassMergingOfKotlinLambdas))
+ .addProgramFiles(getProgramFiles())
.setMinApi(parameters.getApiLevel())
- .noMinification();
+ .apply(
+ builder -> {
+ for (int mainId = 0; mainId < LAMBDA_HOLDER_LIMIT; mainId++) {
+ builder.addKeepClassAndMembersRules(PKG_NAME + ".MainKt" + mainId);
+ }
+ })
+ .addDontWarnJetBrainsNotNullAnnotation()
+ .addHorizontallyMergedClassesInspector(
+ inspector -> {
+ HorizontalClassMergerOptions defaultHorizontalClassMergerOptions =
+ new HorizontalClassMergerOptions();
+ assertEquals(4833, inspector.getSources().size());
+ assertEquals(167, inspector.getTargets().size());
+ assertTrue(
+ inspector.getMergeGroups().stream()
+ .allMatch(
+ mergeGroup ->
+ mergeGroup.size()
+ <= defaultHorizontalClassMergerOptions.getMaxGroupSize()));
+ })
+ .compile();
+ Path path = compileResult.writeToZip();
+ compileResult
+ .run(parameters.getRuntime(), PKG_NAME + ".MainKt0")
+ .assertSuccessWithOutputLines("3");
+ Path oatFile = temp.newFile("out.oat").toPath();
+ ProcessResult processResult =
+ ToolHelper.runDex2OatRaw(path, oatFile, parameters.getRuntime().asDex().getVm());
+ assertEquals(0, processResult.exitCode);
+ assertThat(
+ processResult.stderr, not(containsString("Method exceeds compiler instruction limit")));
+ }
+
+ private List<Path> getProgramFiles() throws IOException {
Path classFiles = temp.newFile("classes.jar").toPath();
List<byte[]> classFileData = new ArrayList<>();
for (int mainId = 0; mainId < LAMBDA_HOLDER_LIMIT; mainId++) {
@@ -71,50 +94,9 @@
for (int lambdaId = 0; lambdaId < LAMBDAS_PER_CLASS_LIMIT; lambdaId++) {
classFileData.add(MainKt$main$1Dump.dump(mainId, lambdaId));
}
- testBuilder.addKeepClassAndMembersRules(PKG_NAME + ".MainKt" + mainId);
}
writeClassFileDataToJar(classFiles, classFileData);
- R8TestCompileResult compileResult =
- testBuilder
- .addProgramFiles(classFiles)
- .addHorizontallyMergedClassesInspector(
- inspector -> {
- if (enableHorizontalClassMergingOfKotlinLambdas) {
- HorizontalClassMergerOptions defaultHorizontalClassMergerOptions =
- new HorizontalClassMergerOptions();
- assertEquals(4833, inspector.getSources().size());
- assertEquals(167, inspector.getTargets().size());
- assertTrue(
- inspector.getMergeGroups().stream()
- .allMatch(
- mergeGroup ->
- mergeGroup.size()
- <= defaultHorizontalClassMergerOptions.getMaxGroupSize()));
- } else {
- inspector.assertNoClassesMerged();
- }
- })
- .addDontWarnJetBrainsNotNullAnnotation()
- .compile();
- Path path = compileResult.writeToZip();
- compileResult
- .run(parameters.getRuntime(), PKG_NAME + ".MainKt0")
- .assertSuccessWithOutputLines("3")
- .inspect(
- codeInspector -> {
- List<FoundClassSubject> lambdaGroups =
- codeInspector.allClasses().stream()
- .filter(c -> c.getFinalName().contains("LambdaGroup"))
- .collect(Collectors.toList());
- assertEquals(
- 1 - BooleanUtils.intValue(enableHorizontalClassMergingOfKotlinLambdas),
- lambdaGroups.size());
- });
- Path oatFile = temp.newFile("out.oat").toPath();
- ProcessResult processResult =
- ToolHelper.runDex2OatRaw(path, oatFile, parameters.getRuntime().asDex().getVm());
- assertEquals(0, processResult.exitCode);
- assertThat(
- processResult.stderr, not(containsString("Method exceeds compiler instruction limit")));
+ return ImmutableList.of(
+ classFiles, ToolHelper.getKotlinStdlibJar(ToolHelper.getKotlinC_1_3_72()));
}
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java
index 663c081..79cef64 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java
@@ -4,24 +4,25 @@
package com.android.tools.r8.kotlin.lambda.b159688129;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
import java.util.List;
-import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -31,26 +32,20 @@
public class LambdaSplitByCodeCorrectnessTest extends AbstractR8KotlinTestBase {
private final TestParameters parameters;
- private final KotlinTargetVersion targetVersion;
private final boolean splitGroup;
- @Parameters(name = "{0}, kotlinc: {2} targetVersion: {1}, splitGroup: {3}")
+ @Parameters(name = "{0}, {1}, splitGroup: {2}")
public static List<Object[]> data() {
return buildParameters(
getTestParameters().withDexRuntimes().withAllApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
BooleanUtils.values());
}
public LambdaSplitByCodeCorrectnessTest(
- TestParameters parameters,
- KotlinTargetVersion targetVersion,
- KotlinCompiler kotlinc,
- boolean splitGroup) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters, boolean splitGroup) {
+ super(kotlinParameters);
this.parameters = parameters;
- this.targetVersion = targetVersion;
this.splitGroup = splitGroup;
}
@@ -67,8 +62,6 @@
testForR8(parameters.getBackend())
.addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addProgramFiles(ktClasses)
- .addOptionsModification(
- options -> options.horizontalClassMergerOptions().disableKotlinLambdaMerging())
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(PKG_NAME + ".SimpleKt")
.addDontWarnJetBrainsNotNullAnnotation()
@@ -77,25 +70,40 @@
b ->
b.addOptionsModification(
internalOptions ->
- // Setting verificationSizeLimitInBytesOverride = 1 will force a a chain
- // having only a single implementation method in each.
- internalOptions.testing.verificationSizeLimitInBytesOverride =
- splitGroup ? 1 : -1))
- .noMinification()
+ // Setting inliningInstructionAllowance = 1 will force each switch branch to
+ // contain an invoke instruction to a private method.
+ internalOptions.inliningInstructionAllowance = 1))
+ .addHorizontallyMergedClassesInspector(
+ inspector ->
+ inspector.assertIsCompleteMergeGroup(
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$1",
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$2",
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$3",
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$4",
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$5",
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$6"))
.allowDiagnosticWarningMessages()
.compile()
.assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
.inspect(
codeInspector -> {
- List<FoundClassSubject> lambdaGroups =
- codeInspector.allClasses().stream()
- .filter(c -> c.getFinalName().contains("LambdaGroup"))
- .collect(Collectors.toList());
- assertEquals(1, lambdaGroups.size());
- FoundClassSubject lambdaGroup = lambdaGroups.get(0);
- List<FoundMethodSubject> invokeChain =
- lambdaGroup.allMethods(method -> method.getFinalName().contains("invoke$"));
- assertEquals(splitGroup ? 5 : 0, invokeChain.size());
+ ClassSubject mergeTarget =
+ codeInspector.clazz(
+ "com.android.tools.r8.kotlin.lambda.b159688129.SimpleKt$main$1");
+ assertThat(mergeTarget, isPresent());
+
+ MethodSubject virtualMethodSubject =
+ mergeTarget.uniqueMethodThatMatches(
+ method -> method.isVirtual() && !method.isSynthetic());
+ assertThat(virtualMethodSubject, isPresent());
+
+ int found = 0;
+ for (FoundMethodSubject directMethodSubject :
+ mergeTarget.allMethods(x -> x.isPrivate() && !x.isSynthetic())) {
+ assertThat(virtualMethodSubject, invokesMethod(directMethodSubject));
+ found++;
+ }
+ assertEquals(splitGroup ? 6 : 0, found);
})
.run(parameters.getRuntime(), PKG_NAME + ".SimpleKt")
.assertSuccessWithOutputLines("Hello1", "Hello2", "Hello3", "Hello4", "Hello5", "Hello6");
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java b/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java
index e158fc7..3765187 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java
@@ -8,8 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNull;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
import com.android.tools.r8.kotlin.KotlinMetadataWriter;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -22,8 +21,8 @@
public abstract class KotlinMetadataTestBase extends AbstractR8KotlinTestBase {
- public KotlinMetadataTestBase(KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ public KotlinMetadataTestBase(KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
}
static final String PKG = KotlinMetadataTestBase.class.getPackage().getName();
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
index b4fd614..b0a30d7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
@@ -4,17 +4,15 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.JvmTestRunResult;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -32,17 +30,16 @@
private static final String PKG_LIB = PKG + ".primitive_type_rewrite_lib";
private static final String PKG_APP = PKG + ".primitive_type_rewrite_app";
- @Parameterized.Parameters(name = "{0}, target: {1}, compiler: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataPrimitiveTypeRewriteTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
index a048351..09c2a9d 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
@@ -4,16 +4,14 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.metadata.metadata_pruned_fields.Main;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -28,17 +26,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataPrunedFieldsTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
index b6d7701..71bd275 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
@@ -4,16 +4,14 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.StringContains.containsString;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
@@ -52,17 +50,16 @@
"staticPrivate",
"staticInternal");
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteAllowAccessModificationTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
index a285149..ebe0dac 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
@@ -4,17 +4,15 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
@@ -58,17 +56,16 @@
private static final String FOO_ORIGINAL_NAME = PKG_LIB + ".Foo";
private static final String FOO_FINAL_NAME = "a.b.c";
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteAnnotationTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
index 8db1944..374c3fd 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
@@ -4,14 +4,12 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.KotlinMetadataWriter;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -27,17 +25,16 @@
private final String EXPECTED = "foo";
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteAnonymousTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
index 4e7d224..16d3765 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
@@ -4,17 +4,15 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertNotNull;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNull;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.KotlinMetadataWriter;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
@@ -37,17 +35,16 @@
private final String EXPECTED =
StringUtils.lines("false", "0", "a", "0.042", "0.42", "42", "442", "1", "2", "42", "42");
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteBoxedTypesTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
index 065d63f..989512b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
@@ -4,12 +4,9 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
@@ -25,17 +22,16 @@
private static final String PKG_LIB = PKG + ".crossinline_anon_lib";
private static final String PKG_APP = PKG + ".crossinline_anon_app";
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteCrossinlineAnonFunctionTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
index 15f68ea..d969f34 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
@@ -4,12 +4,9 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
@@ -25,17 +22,16 @@
private static final String PKG_LIB = PKG + ".crossinline_concrete_lib";
private static final String PKG_APP = PKG + ".crossinline_concrete_app";
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteCrossinlineConcreteFunctionTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
index b43f846..bc8051d 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
@@ -4,12 +4,9 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
@@ -33,17 +30,16 @@
"null",
"New value has been read in CustomDelegate from 'x'");
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteDelegatedPropertyTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java
index 2ccbb3a..3f42968 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java
@@ -4,15 +4,13 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -27,19 +25,18 @@
@RunWith(Parameterized.class)
public class MetadataRewriteDependentKeep extends KotlinMetadataTestBase {
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
private final TestParameters parameters;
public MetadataRewriteDependentKeep(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
index feca0f8..1caec7d 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
@@ -4,14 +4,12 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.graph.DexAnnotationElement;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
@@ -29,19 +27,18 @@
private final Set<String> nullableFieldKeys = Sets.newHashSet("pn", "xs", "xi");
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
private final TestParameters parameters;
public MetadataRewriteDoNotEmitValuesIfEmpty(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
index fbfc10f..91ede26 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -12,10 +11,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -39,17 +37,16 @@
private final String EXPECTED = StringUtils.lines("B.foo(): 42");
private final String PKG_LIB = PKG + ".flexible_upper_bound_lib";
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteFlexibleUpperBoundTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
index c7b9ea6..eebb77f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -11,10 +10,9 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -35,17 +33,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInClasspathTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
index bdcb905..9106a3b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -12,10 +11,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -44,17 +42,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInCompanionTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
index f9124bd..f46402b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -13,10 +12,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -41,17 +39,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInExtensionFunctionTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
index c78cea1..c2a923f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionProperty;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -14,10 +13,9 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -40,17 +38,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInExtensionPropertyTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
index 5c8468d..48044e2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -13,10 +12,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -39,17 +37,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInFunctionTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java
index db348d0..746c690 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -12,10 +11,9 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -39,17 +37,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInFunctionWithDefaultValueTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
index 65207dd..262d8a2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -13,10 +12,9 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -40,17 +38,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInFunctionWithVarargTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java
index f3c59d9..d583ea7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static org.hamcrest.CoreMatchers.anyOf;
@@ -11,10 +10,9 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -32,17 +30,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInLibraryTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java
index 3949d6e..6411cfc 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -16,10 +15,9 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -44,17 +42,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInMultifileClassTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
index 8bb4603..f2aa77d 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -12,10 +11,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -34,17 +32,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInNestedClassTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
index f84fa48..abce684 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
@@ -3,17 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -32,17 +30,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInParameterTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
index af4c9b6..693c7fc 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionProperty;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -14,10 +13,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -38,17 +36,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInPropertyTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
index 0113f19..cb18acb 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
@@ -3,17 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -32,17 +30,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInPropertyTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java
index a4a3a68..7badf74 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.DescriptorUtils.getDescriptorFromKotlinClassifier;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -12,10 +11,9 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -33,17 +31,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInRenamedTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
index c8144f4..dbaf933 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
@@ -3,17 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -32,17 +30,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInReturnTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java
index db927a8..e479bba 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java
@@ -3,12 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
@@ -31,17 +28,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInSealedClassNestedTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java
index ef43f6e..5156b72 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -15,10 +14,9 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
@@ -39,17 +37,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInSealedClassTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
index 9b0da43..ccc94e5 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -11,10 +10,9 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -33,17 +31,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInSuperTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
index e680d6e..98102c5 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isDexClass;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -13,10 +12,9 @@
import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -61,17 +59,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInTypeAliasTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
index acdda5b..097c832 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isDexClass;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -12,10 +11,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -77,17 +75,16 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInTypeArgumentsTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
index ac232d7..d5e9e1a 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
@@ -4,15 +4,13 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNull;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.KotlinMetadataWriter;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.StringUtils;
@@ -34,17 +32,16 @@
private final String EXPECTED = StringUtils.lines("true", "false", "false", "true");
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewriteInlinePropertyTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
index 0558ebc..e03a72c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
@@ -3,12 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -40,12 +39,18 @@
@Parameterized.Parameters(name = "{0}, kotlinc: {1}")
public static List<Object[]> data() {
- return buildParameters(getTestParameters().withCfRuntimes().build(), getKotlinCompilers());
+ // We are testing static methods on interfaces which requires java 8.
+ return buildParameters(
+ getTestParameters().withCfRuntimes().build(),
+ getKotlinTestParameters()
+ .withAllCompilers()
+ .withTargetVersion(KotlinTargetVersion.JAVA_8)
+ .build());
}
- public MetadataRewriteJvmStaticTest(TestParameters parameters, KotlinCompiler kotlinc) {
- // We are testing static methods on interfaces which requires java 8.
- super(KotlinTargetVersion.JAVA_8, kotlinc);
+ public MetadataRewriteJvmStaticTest(
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java
index 056b18b..569d2b7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java
@@ -4,17 +4,15 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestShrinkerBuilder;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -26,12 +24,11 @@
@RunWith(Parameterized.class)
public class MetadataRewriteKeepPathTest extends KotlinMetadataTestBase {
- @Parameterized.Parameters(name = "{0} target: {1}, kotlinc: {2}, keep: {3}")
+ @Parameterized.Parameters(name = "{0}, {1}, keep: {2}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
BooleanUtils.values());
}
@@ -42,11 +39,8 @@
private final boolean keepMetadata;
public MetadataRewriteKeepPathTest(
- TestParameters parameters,
- KotlinTargetVersion targetVersion,
- KotlinCompiler kotlinc,
- boolean keepMetadata) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters, boolean keepMetadata) {
+ super(kotlinParameters);
this.parameters = parameters;
this.keepMetadata = keepMetadata;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
index 74159a6..c8dd873 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
@@ -4,14 +4,12 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
@@ -23,19 +21,17 @@
@RunWith(Parameterized.class)
public class MetadataRewriteKeepTest extends KotlinMetadataTestBase {
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
private final TestParameters parameters;
- public MetadataRewriteKeepTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ public MetadataRewriteKeepTest(TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
index 0b65ec3..99586b1 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
@@ -4,12 +4,9 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
-
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.util.Collection;
@@ -20,19 +17,18 @@
@RunWith(Parameterized.class)
public class MetadataRewritePassThroughTest extends KotlinMetadataTestBase {
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
private final TestParameters parameters;
public MetadataRewritePassThroughTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
index 3d3386c..6d4391f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
@@ -4,16 +4,14 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertEquals;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -37,17 +35,16 @@
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public MetadataRewritePrunedObjectsTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
index 1a2cd73..8111567 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -11,11 +10,10 @@
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -31,17 +29,15 @@
private final TestParameters parameters;
private static final String FOLDER = "lambdas_jstyle_runnable";
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameterized.Parameters(name = "{0}, {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
- public MetadataStripTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ public MetadataStripTest(TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
index e23ac8f..a7886b2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
@@ -9,9 +9,9 @@
import static org.junit.Assert.fail;
import static org.objectweb.asm.Opcodes.ASM7;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.graph.DexAnnotationElement;
@@ -25,6 +25,7 @@
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import java.io.IOException;
import java.util.Arrays;
+import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.junit.Test;
@@ -39,12 +40,18 @@
private final TestParameters parameters;
@Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimesAndApiLevels().build();
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ getKotlinTestParameters()
+ .withCompiler(getKotlinC_1_3_72())
+ .withTargetVersion(KotlinTargetVersion.JAVA_8)
+ .build());
}
- public MetadataVersionNumberBumpTest(TestParameters parameters) {
- super(KotlinTargetVersion.JAVA_8, getKotlinC_1_3_72());
+ public MetadataVersionNumberBumpTest(
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
index ac7eb23..ae80118 100644
--- a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
@@ -4,16 +4,14 @@
package com.android.tools.r8.kotlin.reflection;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
@@ -29,7 +27,6 @@
public class KotlinReflectTest extends KotlinTestBase {
private final TestParameters parameters;
- private final KotlinTargetVersion targetVersion;
private static final String EXPECTED_OUTPUT = "Hello World!";
private static final String PKG = KotlinReflectTest.class.getPackage().getName();
private static final KotlinCompileMemoizer compiledJars =
@@ -40,19 +37,16 @@
DescriptorUtils.getBinaryNameFromJavaType(PKG),
"SimpleReflect" + FileUtils.KT_EXTENSION));
- @Parameters(name = "{0}, target: {1}, kotlinc: {2}")
+ @Parameters(name = "{0}, {1}")
public static List<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
- public KotlinReflectTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ public KotlinReflectTest(TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
- this.targetVersion = targetVersion;
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java
index 92b6b97..47f9463 100644
--- a/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java
@@ -6,15 +6,13 @@
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.hamcrest.CoreMatchers.containsString;
import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
@@ -33,17 +31,15 @@
private final TestParameters parameters;
- @Parameters(name = "{0}")
+ @Parameters(name = "{0}, {1}")
public static List<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
- public SealedClassTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ public SealedClassTest(TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/naming/AbstractR8KotlinNamingTestBase.java b/src/test/java/com/android/tools/r8/naming/AbstractR8KotlinNamingTestBase.java
index ddc2da6..2c3f2bb 100644
--- a/src/test/java/com/android/tools/r8/naming/AbstractR8KotlinNamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/AbstractR8KotlinNamingTestBase.java
@@ -7,10 +7,8 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
-import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FieldSubject;
@@ -21,11 +19,10 @@
protected final boolean minification;
AbstractR8KotlinNamingTestBase(
- KotlinTargetVersion kotlinTargetVersion,
- KotlinCompiler kotlinc,
+ KotlinTestParameters kotlinParameters,
boolean allowAccessModification,
boolean minification) {
- super(kotlinTargetVersion, kotlinc, allowAccessModification);
+ super(kotlinParameters, allowAccessModification);
this.minification = minification;
}
@@ -41,56 +38,27 @@
return classSubject;
}
- protected FieldSubject checkFieldIsRenamed(
- ClassSubject classSubject, String fieldType, String fieldName) {
- FieldSubject fieldSubject = checkFieldIsKept(classSubject, fieldType, fieldName);
- assertThat(fieldSubject, isPresentAndRenamed());
- return fieldSubject;
- }
-
protected FieldSubject checkFieldIsRenamed(ClassSubject classSubject, String fieldName) {
FieldSubject fieldSubject = checkFieldIsKept(classSubject, fieldName);
assertThat(fieldSubject, isPresentAndRenamed());
return fieldSubject;
}
- protected FieldSubject checkFieldIsNotRenamed(
- ClassSubject classSubject, String fieldType, String fieldName) {
- FieldSubject fieldSubject = checkFieldIsKept(classSubject, fieldType, fieldName);
- assertThat(fieldSubject, isPresentAndNotRenamed());
- return fieldSubject;
- }
-
protected FieldSubject checkFieldIsNotRenamed(ClassSubject classSubject, String fieldName) {
FieldSubject fieldSubject = checkFieldIsKept(classSubject, fieldName);
assertThat(fieldSubject, isPresentAndNotRenamed());
return fieldSubject;
}
- protected MethodSubject checkMethodIsRenamed(
- ClassSubject classSubject, MethodSignature methodSignature) {
- MethodSubject methodSubject = checkMethodIsKept(classSubject, methodSignature);
- assertThat(methodSubject, isPresentAndRenamed());
- return methodSubject;
- }
-
protected MethodSubject checkMethodIsRenamed(ClassSubject classSubject, String methodName) {
MethodSubject methodSubject = checkMethodIsKept(classSubject, methodName);
assertThat(methodSubject, isPresentAndRenamed());
return methodSubject;
}
- protected MethodSubject checkMethodIsNotRenamed(
- ClassSubject classSubject, MethodSignature methodSignature) {
- MethodSubject methodSubject = checkMethodIsKept(classSubject, methodSignature);
- assertThat(methodSubject, isPresentAndNotRenamed());
- return methodSubject;
- }
-
protected MethodSubject checkMethodIsNotRenamed(ClassSubject classSubject, String methodName) {
MethodSubject methodSubject = checkMethodIsKept(classSubject, methodName);
assertThat(methodSubject, isPresentAndNotRenamed());
return methodSubject;
}
-
}
diff --git a/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java b/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
index b96ff51..f911ce6 100644
--- a/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
@@ -3,17 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -31,21 +29,17 @@
private final TestParameters parameters;
private final boolean minify;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}, minify: {3}")
+ @Parameterized.Parameters(name = "{0}, {1}, minify: {2}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
BooleanUtils.values());
}
public EnumMinificationKotlinTest(
- TestParameters parameters,
- KotlinTargetVersion targetVersion,
- KotlinCompiler kotlinc,
- boolean minify) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters, boolean minify) {
+ super(kotlinParameters);
this.parameters = parameters;
this.minify = minify;
}
diff --git a/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java b/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
index 7a1b6e4..5d9e78b 100644
--- a/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
+++ b/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
@@ -3,17 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestCompileResult;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.kotlin.TestKotlinClass;
@@ -39,21 +37,19 @@
public class KotlinIntrinsicsIdentifierTest extends AbstractR8KotlinNamingTestBase {
private static final String FOLDER = "intrinsics_identifiers";
- @Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}, minification: {3}")
+ @Parameters(name = "{0}, allowAccessModification: {1}, minification: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(),
- getKotlinCompilers(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
BooleanUtils.values(),
BooleanUtils.values());
}
public KotlinIntrinsicsIdentifierTest(
- KotlinTargetVersion targetVersion,
- KotlinCompiler kotlinc,
+ KotlinTestParameters kotlinParameters,
boolean allowAccessModification,
boolean minification) {
- super(targetVersion, kotlinc, allowAccessModification, minification);
+ super(kotlinParameters, allowAccessModification, minification);
}
private static final KotlinCompileMemoizer compiledJars =
diff --git a/src/test/java/com/android/tools/r8/naming/b139991218/TestRunner.java b/src/test/java/com/android/tools/r8/naming/b139991218/TestRunner.java
index 69f0148..665e410 100644
--- a/src/test/java/com/android/tools/r8/naming/b139991218/TestRunner.java
+++ b/src/test/java/com/android/tools/r8/naming/b139991218/TestRunner.java
@@ -4,8 +4,8 @@
package com.android.tools.r8.naming.b139991218;
-import static junit.framework.TestCase.assertTrue;
-import static org.junit.Assert.assertFalse;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
@@ -14,8 +14,6 @@
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ir.optimize.Inliner.Reason;
import com.android.tools.r8.utils.FileUtils;
-import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.nio.file.Paths;
@@ -63,21 +61,25 @@
options -> {
options.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE);
options.enableClassInlining = false;
+
+ // TODO(b/179019716): Add support for merging in presence of annotations.
+ options.horizontalClassMergerOptions()
+ .skipNoClassesOrMembersWithAnnotationsPolicyForTesting =
+ true;
})
.addDontWarnJetBrainsAnnotations()
+ .addHorizontallyMergedClassesInspector(
+ inspector ->
+ inspector.assertIsCompleteMergeGroup(
+ "com.android.tools.r8.naming.b139991218.Lambda1",
+ "com.android.tools.r8.naming.b139991218.Lambda2"))
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutput(StringUtils.lines("11", "12"))
+ .assertSuccessWithOutputLines("11", "12")
.inspect(
- inspector -> {
- // Ensure that we have created a lambda group and that the lambda classes are now
- // gone.
- boolean foundLambdaGroup = false;
- for (FoundClassSubject allClass : inspector.allClasses()) {
- foundLambdaGroup |= allClass.getOriginalName().contains("LambdaGroup");
- assertFalse(allClass.getOriginalName().contains("b139991218.Lambda"));
- }
- assertTrue(foundLambdaGroup);
- });
+ inspector ->
+ assertThat(
+ inspector.clazz("com.android.tools.r8.naming.b139991218.Lambda1"),
+ isPresent()));
}
}
diff --git a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java
index 94e1e1a..2479dce 100644
--- a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java
@@ -5,7 +5,6 @@
import static com.android.tools.r8.Collectors.toSingle;
import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.containsLinePositions;
import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineFrame;
import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineStack;
@@ -16,11 +15,10 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.naming.retrace.StackTrace;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -44,18 +42,17 @@
private final TestParameters parameters;
- @Parameters(name = "{0}")
+ @Parameters(name = "{0}, {1}")
public static List<Object[]> data() {
// TODO(b/141817471): Extend with compilation modes.
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public KotlinInlineFunctionInSameFileRetraceTests(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionRetraceTest.java b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionRetraceTest.java
index 3827c26..945b732 100644
--- a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionRetraceTest.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.Collectors.toSingle;
import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.containsLinePositions;
import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineFrame;
import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineStack;
@@ -17,11 +16,10 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.naming.retrace.StackTrace;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
@@ -45,18 +43,17 @@
private static final String FILENAME_INLINE_STATIC = "InlineFunction.kt";
private static final String FILENAME_INLINE_INSTANCE = "InlineFunction.kt";
- @Parameters(name = "{0}")
+ @Parameters(name = "{0}, {1}")
public static List<Object[]> data() {
// TODO(b/141817471): Extend with compilation modes.
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers());
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
public KotlinInlineFunctionRetraceTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
index 64ea164..2cc7c96 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.rewrite.assertions;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
@@ -15,8 +14,8 @@
import com.android.tools.r8.AssertionsConfiguration;
import com.android.tools.r8.D8TestBuilder;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ThrowableConsumer;
@@ -63,24 +62,21 @@
private final boolean useJvmAssertions;
private final KotlinCompileMemoizer compiledForAssertions;
- @Parameterized.Parameters(
- name = "{0}, target: {1}, kotlinc: {2}, kotlin-stdlib as library: {3}, -Xassertions=jvm: {4}")
+ @Parameterized.Parameters(name = "{0}, {1}, kotlin-stdlib as library: {2}, -Xassertions=jvm: {3}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
BooleanUtils.values(),
BooleanUtils.values());
}
public AssertionConfigurationKotlinTest(
TestParameters parameters,
- KotlinTargetVersion targetVersion,
- KotlinCompiler kotlinc,
+ KotlinTestParameters kotlinParameters,
boolean kotlinStdlibAsClasspath,
boolean useJvmAssertions) {
- super(targetVersion, kotlinc);
+ super(kotlinParameters);
this.parameters = parameters;
this.kotlinStdlibAsLibrary = kotlinStdlibAsClasspath;
this.useJvmAssertions = useJvmAssertions;
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/ReflectiveAnnotationUseTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/ReflectiveAnnotationUseTest.java
index bc55c55..8eaee28 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/ReflectiveAnnotationUseTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/ReflectiveAnnotationUseTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking.annotations;
-import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static org.hamcrest.CoreMatchers.containsString;
@@ -13,10 +12,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.graph.DexAnnotationElement;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.BooleanUtils;
@@ -62,21 +60,17 @@
private final TestParameters parameters;
private final boolean minify;
- @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}, minify: {3}")
+ @Parameterized.Parameters(name = "{0}, {1}, minify: {2}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values(),
- getKotlinCompilers(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
BooleanUtils.values());
}
public ReflectiveAnnotationUseTest(
- TestParameters parameters,
- KotlinTargetVersion targetVersion,
- KotlinCompiler kotlinc,
- boolean minify) {
- super(targetVersion, kotlinc);
+ TestParameters parameters, KotlinTestParameters kotlinParameters, boolean minify) {
+ super(kotlinParameters);
this.parameters = parameters;
this.minify = minify;
}
diff --git a/src/test/java/com/android/tools/r8/shaking/b134858535/EventPublisherTest.java b/src/test/java/com/android/tools/r8/shaking/b134858535/EventPublisherTest.java
index 6f9c298..5d5a4b9 100644
--- a/src/test/java/com/android/tools/r8/shaking/b134858535/EventPublisherTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/b134858535/EventPublisherTest.java
@@ -51,8 +51,8 @@
.addKeepClassRules(Interface.class)
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
- .addHorizontallyMergedLambdaClassesInspector(
- inspector -> inspector.assertClassNotMerged(EventPublisher$b.class))
+ .addHorizontallyMergedClassesInspector(
+ inspector -> inspector.assertClassesNotMerged(EventPublisher$b.class))
.compile();
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
index cb09a17..491bf9d 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.references.ClassReference;
import java.util.List;
import java.util.function.Consumer;
+import java.util.function.Predicate;
import kotlinx.metadata.jvm.KotlinClassMetadata;
import org.junit.rules.TemporaryFolder;
@@ -38,7 +39,7 @@
}
@Override
- public MethodSubject uniqueInstanceInitializer() {
+ public MethodSubject uniqueMethodThatMatches(Predicate<FoundMethodSubject> predicate) {
return new AbsentMethodSubject();
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index cec4e2b..ee96d6b 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -96,7 +96,11 @@
public abstract MethodSubject method(String returnType, String name, List<String> parameters);
- public abstract MethodSubject uniqueInstanceInitializer();
+ public final MethodSubject uniqueInstanceInitializer() {
+ return uniqueMethodThatMatches(FoundMethodSubject::isInstanceInitializer);
+ }
+
+ public abstract MethodSubject uniqueMethodThatMatches(Predicate<FoundMethodSubject> predicate);
public abstract MethodSubject uniqueMethodWithName(String name);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index 0bfe560..ed04f35 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -46,6 +46,7 @@
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.function.Predicate;
import kotlinx.metadata.jvm.KotlinClassMetadata;
import org.junit.rules.TemporaryFolder;
@@ -128,9 +129,9 @@
}
@Override
- public MethodSubject uniqueInstanceInitializer() {
+ public MethodSubject uniqueMethodThatMatches(Predicate<FoundMethodSubject> predicate) {
MethodSubject methodSubject = null;
- for (FoundMethodSubject candidate : allMethods(FoundMethodSubject::isInstanceInitializer)) {
+ for (FoundMethodSubject candidate : allMethods(predicate)) {
assert methodSubject == null;
methodSubject = candidate;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java
index e90df17..a5c623c 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java
@@ -8,16 +8,25 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import com.android.tools.r8.TestBase;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.horizontalclassmerging.HorizontallyMergedClasses;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.SetUtils;
+import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.Sets;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
public class HorizontallyMergedClassesInspector {
@@ -59,8 +68,32 @@
public HorizontallyMergedClassesInspector assertMergedInto(Class<?> from, Class<?> target) {
assertEquals(
- horizontallyMergedClasses.getMergeTargetOrDefault(toDexType(from, dexItemFactory)),
- toDexType(target, dexItemFactory));
+ horizontallyMergedClasses.getMergeTargetOrDefault(toDexType(from)), toDexType(target));
+ return this;
+ }
+
+ public HorizontallyMergedClassesInspector assertClassesMerged(Collection<Class<?>> classes) {
+ return assertTypesMerged(classes.stream().map(this::toDexType).collect(Collectors.toList()));
+ }
+
+ public HorizontallyMergedClassesInspector assertClassReferencesMerged(
+ Collection<ClassReference> classReferences) {
+ return assertTypesMerged(
+ classReferences.stream().map(this::toDexType).collect(Collectors.toList()));
+ }
+
+ public HorizontallyMergedClassesInspector assertTypesMerged(Collection<DexType> types) {
+ List<DexType> unmerged = new ArrayList<>();
+ for (DexType type : types) {
+ if (!horizontallyMergedClasses.hasBeenMergedOrIsMergeTarget(type)) {
+ unmerged.add(type);
+ }
+ }
+ assertEquals(
+ "Expected the following classes to be merged: "
+ + StringUtils.join(", ", unmerged, DexType::getTypeName),
+ 0,
+ unmerged.size());
return this;
}
@@ -69,52 +102,91 @@
return this;
}
- public HorizontallyMergedClassesInspector assertClassNotMerged(Class<?> clazz) {
- assertFalse(
- horizontallyMergedClasses.hasBeenMergedIntoDifferentType(toDexType(clazz, dexItemFactory)));
- return this;
- }
-
- public HorizontallyMergedClassesInspector assertClassesNotMerged(Collection<Class<?>> classes) {
- for (Class<?> clazz : classes) {
- assertClassNotMerged(clazz);
- }
- return this;
- }
-
public HorizontallyMergedClassesInspector assertClassesNotMerged(Class<?>... classes) {
return assertClassesNotMerged(Arrays.asList(classes));
}
- public HorizontallyMergedClassesInspector assertClassNotMergedIntoDifferentType(Class<?> clazz) {
- assertFalse(
- horizontallyMergedClasses.hasBeenMergedIntoDifferentType(toDexType(clazz, dexItemFactory)));
- return this;
+ public HorizontallyMergedClassesInspector assertClassesNotMerged(Collection<Class<?>> classes) {
+ return assertTypesNotMerged(classes.stream().map(this::toDexType).collect(Collectors.toList()));
}
- public HorizontallyMergedClassesInspector assertMerged(Class<?> clazz) {
- assertTrue(
- horizontallyMergedClasses.hasBeenMergedOrIsMergeTarget(toDexType(clazz, dexItemFactory)));
- return this;
+ public HorizontallyMergedClassesInspector assertClassReferencesNotMerged(
+ ClassReference... classReferences) {
+ return assertClassReferencesNotMerged(Arrays.asList(classReferences));
}
- public HorizontallyMergedClassesInspector assertMerged(Class<?>... classes) {
- for (Class<?> clazz : classes) {
- assertMerged(clazz);
+ public HorizontallyMergedClassesInspector assertClassReferencesNotMerged(
+ Collection<ClassReference> classReferences) {
+ return assertTypesNotMerged(
+ classReferences.stream().map(this::toDexType).collect(Collectors.toList()));
+ }
+
+ public HorizontallyMergedClassesInspector assertTypesNotMerged(DexType... types) {
+ return assertTypesNotMerged(Arrays.asList(types));
+ }
+
+ public HorizontallyMergedClassesInspector assertTypesNotMerged(Collection<DexType> types) {
+ for (DexType type : types) {
+ assertTrue(type.isClassType());
+ assertFalse(horizontallyMergedClasses.hasBeenMergedOrIsMergeTarget(type));
}
return this;
}
- public HorizontallyMergedClassesInspector assertMergedIntoDifferentType(Class<?> clazz) {
- assertTrue(
- horizontallyMergedClasses.hasBeenMergedIntoDifferentType(toDexType(clazz, dexItemFactory)));
+ public HorizontallyMergedClassesInspector assertIsCompleteMergeGroup(String... typeNames) {
+ return assertIsCompleteMergeGroup(
+ Stream.of(typeNames).map(Reference::classFromTypeName).collect(Collectors.toList()));
+ }
+
+ public HorizontallyMergedClassesInspector assertIsCompleteMergeGroup(
+ Collection<ClassReference> classReferences) {
+ assertFalse(classReferences.isEmpty());
+ List<DexType> types =
+ classReferences.stream().map(this::toDexType).collect(Collectors.toList());
+ DexType uniqueTarget = null;
+ for (DexType type : types) {
+ if (horizontallyMergedClasses.isMergeTarget(type)) {
+ if (uniqueTarget == null) {
+ uniqueTarget = type;
+ } else {
+ fail(
+ "Expected a single merge target, but found "
+ + type.getTypeName()
+ + " and "
+ + uniqueTarget.getTypeName());
+ }
+ }
+ }
+ if (uniqueTarget == null) {
+ for (DexType type : types) {
+ if (horizontallyMergedClasses.hasBeenMergedIntoDifferentType(type)) {
+ fail(
+ "Expected merge target "
+ + horizontallyMergedClasses.getMergeTargetOrDefault(type).getTypeName()
+ + " to be in merge group");
+ }
+ }
+ fail("Expected to find a merge target, but none found");
+ }
+ Set<DexType> sources = horizontallyMergedClasses.getSourcesFor(uniqueTarget);
+ assertEquals(
+ "Expected to find "
+ + (classReferences.size() - 1)
+ + " source(s) for merge target "
+ + uniqueTarget.getTypeName()
+ + ", but only found: "
+ + StringUtils.join(", ", sources, DexType::getTypeName),
+ classReferences.size() - 1,
+ sources.size());
+ assertTrue(types.containsAll(sources));
return this;
}
- public HorizontallyMergedClassesInspector assertMergedIntoDifferentType(Class<?>... classes) {
- for (Class<?> clazz : classes) {
- assertMergedIntoDifferentType(clazz);
- }
- return this;
+ private DexType toDexType(Class<?> clazz) {
+ return TestBase.toDexType(clazz, dexItemFactory);
+ }
+
+ private DexType toDexType(ClassReference classReference) {
+ return TestBase.toDexType(classReference, dexItemFactory);
}
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedLambdaClassesInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedLambdaClassesInspector.java
deleted file mode 100644
index 619b415..0000000
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedLambdaClassesInspector.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2020, 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.utils.codeinspector;
-
-import static com.android.tools.r8.TestBase.toDexType;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
-import java.util.Set;
-import java.util.function.BiConsumer;
-
-public class HorizontallyMergedLambdaClassesInspector {
-
- private final DexItemFactory dexItemFactory;
- private final HorizontallyMergedLambdaClasses horizontallyMergedLambdaClasses;
-
- public HorizontallyMergedLambdaClassesInspector(
- DexItemFactory dexItemFactory,
- HorizontallyMergedLambdaClasses horizontallyMergedLambdaClasses) {
- this.dexItemFactory = dexItemFactory;
- this.horizontallyMergedLambdaClasses = horizontallyMergedLambdaClasses;
- }
-
- public HorizontallyMergedLambdaClassesInspector assertMerged(Class<?> clazz) {
- assertTrue(
- horizontallyMergedLambdaClasses.hasBeenMergedIntoDifferentType(
- toDexType(clazz, dexItemFactory)));
- return this;
- }
-
- public HorizontallyMergedLambdaClassesInspector assertMerged(Class<?>... classes) {
- for (Class<?> clazz : classes) {
- assertMerged(clazz);
- }
- return this;
- }
-
- public HorizontallyMergedLambdaClassesInspector assertClassNotMerged(Class<?> clazz) {
- assertFalse(
- horizontallyMergedLambdaClasses.hasBeenMergedIntoDifferentType(
- toDexType(clazz, dexItemFactory)));
- return this;
- }
-
- public void forEachMergeGroup(BiConsumer<Set<DexType>, DexType> consumer) {
- horizontallyMergedLambdaClasses.forEachMergeGroup(consumer);
- }
-}