IncrementalShrinker extends AbstractShrinker<T> { public void incrementalRun( @NonNull Iterable<TransformInput> inputs, @NonNull TransformOutputProvider output) throws IOException, IncrementalRunImpossibleException { final Set<T> classesToWrite = Sets.newConcurrentHashSet(); final Set<File> classFilesToDelete = Sets.newConcurrentHashSet(); final Set<PostProcessingData.UnresolvedReference<T>> unresolvedReferences = Sets.newConcurrentHashSet(); Stopwatch stopwatch = Stopwatch.createStarted(); SetMultimap<T, String> oldState = resetState(); logTime("resetState()", stopwatch); processInputs(inputs, classesToWrite, unresolvedReferences); logTime("processInputs", stopwatch); finishGraph(unresolvedReferences); logTime("finish graph", stopwatch); setCounters(CounterSet.SHRINK); logTime("set counters", stopwatch); chooseClassesToWrite(inputs, output, classesToWrite, classFilesToDelete, oldState); logTime("choose classes", stopwatch); updateClassFiles(classesToWrite, classFilesToDelete, inputs, output); logTime("update class files", stopwatch); mGraph.saveState(); logTime("save state", stopwatch); } IncrementalShrinker(
            WaitableExecutor<Void> executor,
            ShrinkerGraph<T> graph,
            ShrinkerLogger shrinkerLogger); void incrementalRun(
            @NonNull Iterable<TransformInput> inputs,
            @NonNull TransformOutputProvider output);  }
@Test public void simple_testIncrementalUpdate() throws Exception { Files.write(Simple.aaa(), new File(mTestPackageDir, "Aaa.class")); Files.write(Simple.bbb(), new File(mTestPackageDir, "Bbb.class")); Files.write(Simple.main1(), new File(mTestPackageDir, "Main.class")); Files.write(TestClasses.emptyClass("NotUsed"), new File(mTestPackageDir, "NotUsed.class")); fullRun("Main", "main:()V"); assertTrue(new File(mIncrementalDir, "shrinker.bin").exists()); assertMembersLeft("Main", "main:()V"); assertMembersLeft("Aaa", "<init>:()V", "m1:()V"); assertMembersLeft("Bbb", "<init>:()V"); assertClassSkipped("NotUsed"); long timestampBbb = getOutputClassFile("Bbb").lastModified(); long timestampMain = getOutputClassFile("Main").lastModified(); Thread.sleep(1000); Files.write(Simple.main2(), new File(mTestPackageDir, "Main.class")); incrementalRun(ImmutableMap.of("Main", Status.CHANGED)); assertMembersLeft("Main", "main:()V"); assertMembersLeft("Aaa", "<init>:()V", "m2:()V"); assertMembersLeft("Bbb", "<init>:()V"); assertClassSkipped("NotUsed"); assertTrue(timestampMain < getOutputClassFile("Main").lastModified()); assertEquals(timestampBbb, getOutputClassFile("Bbb").lastModified()); }
@Test public void simple_testIncrementalUpdate_methodAdded() throws Exception { Files.write(Simple.aaa(), new File(mTestPackageDir, "Aaa.class")); Files.write(Simple.bbb(), new File(mTestPackageDir, "Bbb.class")); Files.write(Simple.main1(), new File(mTestPackageDir, "Main.class")); Files.write(TestClasses.emptyClass("NotUsed"), new File(mTestPackageDir, "NotUsed.class")); fullRun("Main", "main:()V"); Files.write(Simple.main_extraMethod(), new File(mTestPackageDir, "Main.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("test/Main.extraMain:()V added"); incrementalRun(ImmutableMap.of("Main", Status.CHANGED)); }
@Test public void simple_testIncrementalUpdate_methodRemoved() throws Exception { Files.write(Simple.aaa(), new File(mTestPackageDir, "Aaa.class")); Files.write(Simple.bbb(), new File(mTestPackageDir, "Bbb.class")); Files.write(Simple.main_extraMethod(), new File(mTestPackageDir, "Main.class")); Files.write(TestClasses.emptyClass("NotUsed"), new File(mTestPackageDir, "NotUsed.class")); fullRun("Main", "main:()V"); Files.write(Simple.main1(), new File(mTestPackageDir, "Main.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("test/Main.extraMain:()V removed"); incrementalRun(ImmutableMap.of("Main", Status.CHANGED)); }
@Test public void simple_testIncrementalUpdate_fieldAdded() throws Exception { Files.write(Simple.aaa(), new File(mTestPackageDir, "Aaa.class")); Files.write(Simple.bbb(), new File(mTestPackageDir, "Bbb.class")); Files.write(Simple.main1(), new File(mTestPackageDir, "Main.class")); Files.write(TestClasses.emptyClass("NotUsed"), new File(mTestPackageDir, "NotUsed.class")); fullRun("Main", "main:()V"); Files.write(Simple.main_extraField(), new File(mTestPackageDir, "Main.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("test/Main.sString:Ljava/lang/String; added"); incrementalRun(ImmutableMap.of("Main", Status.CHANGED)); }
@Test public void simple_testIncrementalUpdate_fieldRemoved() throws Exception { Files.write(Simple.aaa(), new File(mTestPackageDir, "Aaa.class")); Files.write(Simple.bbb(), new File(mTestPackageDir, "Bbb.class")); Files.write(Simple.main_extraField(), new File(mTestPackageDir, "Main.class")); Files.write(TestClasses.emptyClass("NotUsed"), new File(mTestPackageDir, "NotUsed.class")); fullRun("Main", "main:()V"); Files.write(Simple.main1(), new File(mTestPackageDir, "Main.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("test/Main.sString:Ljava/lang/String; removed"); incrementalRun(ImmutableMap.of("Main", Status.CHANGED)); }
@Test public void simple_testIncrementalUpdate_classAdded() throws Exception { Files.write(Simple.aaa(), new File(mTestPackageDir, "Aaa.class")); Files.write(Simple.bbb(), new File(mTestPackageDir, "Bbb.class")); Files.write(Simple.main1(), new File(mTestPackageDir, "Main.class")); fullRun("Main", "main:()V"); Files.write(TestClasses.emptyClass("NotUsed"), new File(mTestPackageDir, "NotUsed.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage(FileUtils.toSystemDependentPath("test/NotUsed.class") + " added"); incrementalRun(ImmutableMap.of( "Main", Status.CHANGED, "NotUsed", Status.ADDED)); }
@Test public void simple_testIncrementalUpdate_classRemoved() throws Exception { File notUsedClass = new File(mTestPackageDir, "NotUsed.class"); Files.write(Simple.aaa(), new File(mTestPackageDir, "Aaa.class")); Files.write(Simple.bbb(), new File(mTestPackageDir, "Bbb.class")); Files.write(Simple.main1(), new File(mTestPackageDir, "Main.class")); Files.write(TestClasses.emptyClass("NotUsed"), notUsedClass); fullRun("Main", "main:()V"); FileUtils.delete(notUsedClass); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage( FileUtils.toSystemDependentPath("test/NotUsed.class") + " removed"); incrementalRun(ImmutableMap.of( "Main", Status.CHANGED, "NotUsed", Status.REMOVED)); }
@Test public void simple_testIncrementalUpdate_superclassChanged() throws Exception { Files.write(Simple.aaa(), new File(mTestPackageDir, "Aaa.class")); Files.write(Simple.bbb(), new File(mTestPackageDir, "Bbb.class")); Files.write(Simple.main1(), new File(mTestPackageDir, "Main.class")); fullRun("Main", "main:()V"); Files.write(Simple.bbb_extendsAaa(), new File(mTestPackageDir, "Bbb.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("test/Bbb superclass changed"); incrementalRun(ImmutableMap.of( "Bbb", Status.CHANGED)); }
@Test public void simple_testIncrementalUpdate_interfacesChanged() throws Exception { Files.write(Simple.aaa(), new File(mTestPackageDir, "Aaa.class")); Files.write(Simple.bbb(), new File(mTestPackageDir, "Bbb.class")); Files.write(Simple.main1(), new File(mTestPackageDir, "Main.class")); fullRun("Main", "main:()V"); Files.write(Simple.bbb_serializable(), new File(mTestPackageDir, "Bbb.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("test/Bbb interfaces changed"); incrementalRun(ImmutableMap.of( "Bbb", Status.CHANGED)); }
@Test public void simple_testIncrementalUpdate_methodModifiersChanged() throws Exception { Files.write(Simple.aaa(), new File(mTestPackageDir, "Aaa.class")); Files.write(Simple.bbb(), new File(mTestPackageDir, "Bbb.class")); Files.write(Simple.main1(), new File(mTestPackageDir, "Main.class")); fullRun("Main", "main:()V"); Files.write(Simple.bbb_packagePrivateConstructor(), new File(mTestPackageDir, "Bbb.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("test/Bbb.<init>:()V modifiers changed"); incrementalRun(ImmutableMap.of( "Bbb", Status.CHANGED)); }
@Test public void simple_testIncrementalUpdate_fieldModifiersChanged() throws Exception { Files.write(Simple.aaa(), new File(mTestPackageDir, "Aaa.class")); Files.write(Simple.bbb(), new File(mTestPackageDir, "Bbb.class")); Files.write(Simple.main_extraField(), new File(mTestPackageDir, "Main.class")); fullRun("Main", "main:()V"); Files.write(Simple.main_extraField_private(), new File(mTestPackageDir, "Main.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("test/Main.sString:Ljava/lang/String; modifiers changed"); incrementalRun(ImmutableMap.of( "Main", Status.CHANGED)); }
@Test public void simple_testIncrementalUpdate_classModifiersChanged() throws Exception { Files.write(Simple.aaa(), new File(mTestPackageDir, "Aaa.class")); Files.write(Simple.bbb(), new File(mTestPackageDir, "Bbb.class")); Files.write(Simple.main1(), new File(mTestPackageDir, "Main.class")); fullRun("Main", "main:()V"); Files.write(Simple.bbb_packagePrivate(), new File(mTestPackageDir, "Bbb.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("test/Bbb modifiers changed"); incrementalRun(ImmutableMap.of( "Bbb", Status.CHANGED)); }
@Test public void simple_testIncrementalUpdate_classAnnotationAdded() throws Exception { Files.write(Annotations.main_annotatedClass(), new File(mTestPackageDir, "Main.class")); Files.write(TestClasses.Annotations.myAnnotation(), new File(mTestPackageDir, "MyAnnotation.class")); Files.write(TestClasses.Annotations.nested(), new File(mTestPackageDir, "Nested.class")); Files.write(TestClasses.Annotations.myEnum(), new File(mTestPackageDir, "MyEnum.class")); Files.write(TestClasses.emptyClass("SomeClass"), new File(mTestPackageDir, "SomeClass.class")); Files.write(TestClasses.emptyClass("SomeOtherClass"), new File(mTestPackageDir, "SomeOtherClass.class")); fullRun("Main", "main:()V"); Files.write(Annotations.main_noAnnotations(), new File(mTestPackageDir, "Main.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("Annotation test/MyAnnotation on test/Main removed"); incrementalRun(ImmutableMap.of("Main", Status.CHANGED)); }
@Test public void simple_testIncrementalUpdate_classAnnotationRemoved() throws Exception { Files.write(Annotations.main_noAnnotations(), new File(mTestPackageDir, "Main.class")); Files.write(TestClasses.Annotations.myAnnotation(), new File(mTestPackageDir, "MyAnnotation.class")); Files.write(TestClasses.Annotations.nested(), new File(mTestPackageDir, "Nested.class")); Files.write(TestClasses.Annotations.myEnum(), new File(mTestPackageDir, "MyEnum.class")); Files.write(TestClasses.emptyClass("SomeClass"), new File(mTestPackageDir, "SomeClass.class")); Files.write(TestClasses.emptyClass("SomeOtherClass"), new File(mTestPackageDir, "SomeOtherClass.class")); fullRun("Main", "main:()V"); Files.write(Annotations.main_annotatedClass(), new File(mTestPackageDir, "Main.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("Annotation test/MyAnnotation on test/Main added"); incrementalRun(ImmutableMap.of("Main", Status.CHANGED)); }
@Test public void simple_testIncrementalUpdate_methodAnnotationAdded() throws Exception { Files.write(Annotations.main_noAnnotations(), new File(mTestPackageDir, "Main.class")); Files.write(TestClasses.Annotations.myAnnotation(), new File(mTestPackageDir, "MyAnnotation.class")); Files.write(TestClasses.Annotations.nested(), new File(mTestPackageDir, "Nested.class")); Files.write(TestClasses.Annotations.myEnum(), new File(mTestPackageDir, "MyEnum.class")); Files.write(TestClasses.emptyClass("SomeClass"), new File(mTestPackageDir, "SomeClass.class")); Files.write(TestClasses.emptyClass("SomeOtherClass"), new File(mTestPackageDir, "SomeOtherClass.class")); fullRun("Main", "main:()V"); Files.write(Annotations.main_annotatedMethod(), new File(mTestPackageDir, "Main.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("Annotation test/MyAnnotation on test/Main.main added"); incrementalRun(ImmutableMap.of("Main", Status.CHANGED)); }
@Test public void simple_testIncrementalUpdate_methodAnnotationRemoved() throws Exception { Files.write(Annotations.main_annotatedMethod(), new File(mTestPackageDir, "Main.class")); Files.write(TestClasses.Annotations.myAnnotation(), new File(mTestPackageDir, "MyAnnotation.class")); Files.write(TestClasses.Annotations.nested(), new File(mTestPackageDir, "Nested.class")); Files.write(TestClasses.Annotations.myEnum(), new File(mTestPackageDir, "MyEnum.class")); Files.write(TestClasses.emptyClass("SomeClass"), new File(mTestPackageDir, "SomeClass.class")); Files.write(TestClasses.emptyClass("SomeOtherClass"), new File(mTestPackageDir, "SomeOtherClass.class")); fullRun("Main", "main:()V"); Files.write(Annotations.main_noAnnotations(), new File(mTestPackageDir, "Main.class")); mException.expect(IncrementalRunImpossibleException.class); mException.expectMessage("Annotation test/MyAnnotation on test/Main.main removed"); incrementalRun(ImmutableMap.of("Main", Status.CHANGED)); }
@Test public void cycle() throws Exception { Files.write(Cycle.main1(), new File(mTestPackageDir, "Main.class")); Files.write(Cycle.cycleOne(), new File(mTestPackageDir, "CycleOne.class")); Files.write(Cycle.cycleTwo(), new File(mTestPackageDir, "CycleTwo.class")); Files.write(TestClasses.emptyClass("NotUsed"), new File(mTestPackageDir, "NotUsed.class")); fullRun("Main", "main:()V"); assertTrue(new File(mIncrementalDir, "shrinker.bin").exists()); assertMembersLeft("Main", "main:()V"); assertMembersLeft("CycleOne", "<init>:()V"); assertMembersLeft("CycleTwo", "<init>:()V"); assertClassSkipped("NotUsed"); byte[] mainBytes = Files.toByteArray(getOutputClassFile("Main")); Files.write(Cycle.main2(), new File(mTestPackageDir, "Main.class")); incrementalRun(ImmutableMap.of("Main", Status.CHANGED)); assertMembersLeft("Main", "main:()V"); assertClassSkipped("CycleOne"); assertClassSkipped("CycleTwo"); assertClassSkipped("NotUsed"); assertNotEquals(mainBytes, Files.toByteArray(getOutputClassFile("Main"))); Files.write(Cycle.main1(), new File(mTestPackageDir, "Main.class")); incrementalRun(ImmutableMap.of("Main", Status.CHANGED)); assertMembersLeft("Main", "main:()V"); assertMembersLeft("CycleOne", "<init>:()V"); assertMembersLeft("CycleTwo", "<init>:()V"); assertClassSkipped("NotUsed"); }
@Test public void interfaces_implementationFromSuperclass() throws Exception { Files.write(Interfaces.main(), new File(mTestPackageDir, "Main.class")); Files.write(Interfaces.myInterface(), new File(mTestPackageDir, "MyInterface.class")); Files.write(Interfaces.myCharSequence(), new File(mTestPackageDir, "MyCharSequence.class")); Files.write(Interfaces.myImpl(), new File(mTestPackageDir, "MyImpl.class")); Files.write(Interfaces.namedRunnable(), new File(mTestPackageDir, "NamedRunnable.class")); Files.write(Interfaces.namedRunnableImpl(), new File(mTestPackageDir, "NamedRunnableImpl.class")); Files.write(Interfaces.doesSomething(), new File(mTestPackageDir, "DoesSomething.class")); Files.write( Interfaces.implementationFromSuperclass(), new File(mTestPackageDir, "ImplementationFromSuperclass.class")); fullRun( "Main", "useImplementationFromSuperclass:(Ltest/ImplementationFromSuperclass;)V", "useMyInterface:(Ltest/MyInterface;)V"); assertMembersLeft( "Main", "useImplementationFromSuperclass:(Ltest/ImplementationFromSuperclass;)V", "useMyInterface:(Ltest/MyInterface;)V"); assertMembersLeft("ImplementationFromSuperclass"); assertMembersLeft( "MyInterface", "doSomething:(Ljava/lang/Object;)V"); assertClassSkipped("MyImpl"); assertClassSkipped("MyCharSequence"); assertMembersLeft( "DoesSomething", "doSomething:(Ljava/lang/Object;)V"); assertImplements("ImplementationFromSuperclass", "test/MyInterface"); incrementalRun(ImmutableMap.of("ImplementationFromSuperclass", Status.CHANGED)); }