blob: dc8b7588dcd3a95b979ad30dea20c5ac06c3bc1b [file] [log] [blame]
/*
* Copyright (C) 2017 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dagger.internal.codegen;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
import com.google.testing.compile.Compilation;
import com.google.testing.compile.CompilationSubject;
import com.google.testing.compile.JavaFileObjects;
import java.util.Collection;
import javax.tools.JavaFileObject;
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 DelegateBindingExpressionTest {
@Parameters(name = "{0}")
public static Collection<Object[]> parameters() {
return CompilerMode.TEST_PARAMETERS;
}
private final CompilerMode compilerMode;
public DelegateBindingExpressionTest(CompilerMode compilerMode) {
this.compilerMode = compilerMode;
}
private static final JavaFileObject REGULAR_SCOPED =
JavaFileObjects.forSourceLines(
"test.RegularScoped",
"package test;",
"",
"import javax.inject.Scope;",
"import javax.inject.Inject;",
"",
"@RegularScoped.CustomScope",
"class RegularScoped {",
" @Inject RegularScoped() {}",
"",
" @Scope @interface CustomScope {}",
"}");
private static final JavaFileObject REUSABLE_SCOPED =
JavaFileObjects.forSourceLines(
"test.ReusableScoped",
"package test;",
"",
"import dagger.Reusable;",
"import javax.inject.Inject;",
"",
"@Reusable",
"class ReusableScoped {",
" @Inject ReusableScoped() {}",
"}");
private static final JavaFileObject UNSCOPED =
JavaFileObjects.forSourceLines(
"test.Unscoped",
"package test;",
"",
"import javax.inject.Inject;",
"",
"class Unscoped {",
" @Inject Unscoped() {}",
"}");
private static final JavaFileObject COMPONENT =
JavaFileObjects.forSourceLines(
"test.TestComponent",
"package test;",
"",
"import dagger.Component;",
"",
"@Component(modules = TestModule.class)",
"@RegularScoped.CustomScope",
"interface TestComponent {",
" @Qualifier(RegularScoped.class)",
" Object regular();",
"",
" @Qualifier(ReusableScoped.class)",
" Object reusable();",
"",
" @Qualifier(Unscoped.class)",
" Object unscoped();",
"}");
private static final JavaFileObject QUALIFIER =
JavaFileObjects.forSourceLines(
"test.Qualifier",
"package test;",
"",
"@javax.inject.Qualifier",
"@interface Qualifier {",
" Class<?> value();",
"}");
@Test
public void toDoubleCheck() {
JavaFileObject module =
JavaFileObjects.forSourceLines(
"test.TestModule",
"package test;",
"",
"import dagger.Binds;",
"import dagger.Module;",
"",
"@Module",
"interface TestModule {",
" @Binds @RegularScoped.CustomScope @Qualifier(RegularScoped.class)",
" Object regular(RegularScoped delegate);",
"",
" @Binds @RegularScoped.CustomScope @Qualifier(ReusableScoped.class)",
" Object reusable(ReusableScoped delegate);",
"",
" @Binds @RegularScoped.CustomScope @Qualifier(Unscoped.class)",
" Object unscoped(Unscoped delegate);",
"}");
assertThatCompilationWithModule(module)
.generatedSourceFile("test.DaggerTestComponent")
.containsElementsIn(
compilerMode
.javaFileBuilder("test.DaggerTestComponent")
.addLines(
"package test;",
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Object regularScoped = new MemoizedSentinel();",
" private volatile ReusableScoped reusableScoped;",
"",
" private RegularScoped regularScoped() {",
" Object local = regularScoped;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
" local = regularScoped;",
" if (local instanceof MemoizedSentinel) {",
" local = new RegularScoped();",
" regularScoped = DoubleCheck.reentrantCheck(regularScoped, local);",
" }",
" }",
" }",
" return (RegularScoped) local;",
" }",
"",
" private ReusableScoped reusableScoped() {",
" Object local = reusableScoped;",
" if (local == null) {",
" local = new ReusableScoped();",
" reusableScoped = (ReusableScoped) local;",
" }",
" return (ReusableScoped) local;",
" }",
"")
.addLinesIn(
DEFAULT_MODE,
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
" this.regularScopedProvider = ",
" DoubleCheck.provider(RegularScoped_Factory.create());",
" this.reusableScopedProvider = ",
" SingleCheck.provider(ReusableScoped_Factory.create());",
" this.reusableProvider = DoubleCheck.provider(",
" (Provider) reusableScopedProvider);",
" this.unscopedProvider = DoubleCheck.provider(",
" (Provider) Unscoped_Factory.create());",
" }")
.addLines( //
"}")
.build());
}
@Test
public void toSingleCheck() {
JavaFileObject module =
JavaFileObjects.forSourceLines(
"test.TestModule",
"package test;",
"",
"import dagger.Binds;",
"import dagger.Module;",
"import dagger.Reusable;",
"",
"@Module",
"interface TestModule {",
" @Binds @Reusable @Qualifier(RegularScoped.class)",
" Object regular(RegularScoped delegate);",
"",
" @Binds @Reusable @Qualifier(ReusableScoped.class)",
" Object reusable(ReusableScoped delegate);",
"",
" @Binds @Reusable @Qualifier(Unscoped.class)",
" Object unscoped(Unscoped delegate);",
"}");
assertThatCompilationWithModule(module)
.generatedSourceFile("test.DaggerTestComponent")
.containsElementsIn(
compilerMode
.javaFileBuilder("test.DaggerTestComponent")
.addLines(
"package test;",
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Object regularScoped = new MemoizedSentinel();",
" private volatile ReusableScoped reusableScoped;",
"",
" private RegularScoped regularScoped() {",
" Object local = regularScoped;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
" local = regularScoped;",
" if (local instanceof MemoizedSentinel) {",
" local = new RegularScoped();",
" regularScoped = DoubleCheck.reentrantCheck(regularScoped, local);",
" }",
" }",
" }",
" return (RegularScoped) local;",
" }",
"",
" private ReusableScoped reusableScoped() {",
" Object local = reusableScoped;",
" if (local == null) {",
" local = new ReusableScoped();",
" reusableScoped = (ReusableScoped) local;",
" }",
" return (ReusableScoped) local;",
" }",
"")
.addLinesIn(
DEFAULT_MODE,
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
" this.regularScopedProvider = ",
" DoubleCheck.provider(RegularScoped_Factory.create());",
" this.reusableScopedProvider = ",
" SingleCheck.provider(ReusableScoped_Factory.create());",
" this.unscopedProvider = SingleCheck.provider(",
" (Provider) Unscoped_Factory.create());",
" }")
.addLines( //
"}")
.build());
}
@Test
public void toUnscoped() {
JavaFileObject module =
JavaFileObjects.forSourceLines(
"test.TestModule",
"package test;",
"",
"import dagger.Binds;",
"import dagger.Module;",
"",
"@Module",
"interface TestModule {",
" @Binds @Qualifier(RegularScoped.class)",
" Object regular(RegularScoped delegate);",
"",
" @Binds @Qualifier(ReusableScoped.class)",
" Object reusable(ReusableScoped delegate);",
"",
" @Binds @Qualifier(Unscoped.class)",
" Object unscoped(Unscoped delegate);",
"}");
assertThatCompilationWithModule(module)
.generatedSourceFile("test.DaggerTestComponent")
.containsElementsIn(
compilerMode
.javaFileBuilder("test.DaggerTestComponent")
.addLines(
"package test;",
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Object regularScoped = new MemoizedSentinel();",
" private volatile ReusableScoped reusableScoped;",
"",
" private RegularScoped regularScoped() {",
" Object local = regularScoped;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
" local = regularScoped;",
" if (local instanceof MemoizedSentinel) {",
" local = new RegularScoped();",
" regularScoped = DoubleCheck.reentrantCheck(regularScoped, local);",
" }",
" }",
" }",
" return (RegularScoped) local;",
" }",
"",
" private ReusableScoped reusableScoped() {",
" Object local = reusableScoped;",
" if (local == null) {",
" local = new ReusableScoped();",
" reusableScoped = (ReusableScoped) local;",
" }",
" return (ReusableScoped) local;",
" }",
"")
.addLinesIn(
DEFAULT_MODE,
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
" this.regularScopedProvider = ",
" DoubleCheck.provider(RegularScoped_Factory.create());",
" this.reusableScopedProvider = ",
" SingleCheck.provider(ReusableScoped_Factory.create());",
" }")
.addLines( //
"}")
.build());
}
@Test
public void castNeeded_rawTypes_Provider_get() {
JavaFileObject accessibleSupertype =
JavaFileObjects.forSourceLines(
"other.Supertype",
"package other;",
"",
// accessible from the component, but the subtype is not
"public interface Supertype {}");
JavaFileObject inaccessibleSubtype =
JavaFileObjects.forSourceLines(
"other.Subtype",
"package other;",
"",
"import javax.inject.Inject;",
"import javax.inject.Singleton;",
"",
"@Singleton",
"class Subtype implements Supertype {",
" @Inject Subtype() {}",
"}");
JavaFileObject module =
JavaFileObjects.forSourceLines(
"other.SupertypeModule",
"package other;",
"",
"import dagger.Binds;",
"import dagger.Module;",
"",
"@Module",
"public interface SupertypeModule {",
" @Binds Supertype to(Subtype subtype);",
"}");
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.TestComponent",
"package test;",
"",
"import dagger.Component;",
"import javax.inject.Singleton;",
"",
"@Singleton",
"@Component(modules = other.SupertypeModule.class)",
"interface TestComponent {",
" other.Supertype supertype();",
"}");
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(accessibleSupertype, inaccessibleSubtype, module, component);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
.containsElementsIn(
compilerMode
.javaFileBuilder("test.DaggerTestComponent")
.addLines(
"package test;",
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
DEFAULT_MODE,
" @SuppressWarnings(\"rawtypes\")",
" private Provider subtypeProvider;",
"",
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
" this.subtypeProvider = DoubleCheck.provider(Subtype_Factory.create());",
" }",
"",
" @Override",
" public Supertype supertype() {",
" return (Supertype) subtypeProvider.get();",
" }")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Object subtype = new MemoizedSentinel();",
"",
" private Object subtype() {",
" Object local = subtype;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
" local = subtype;",
" if (local instanceof MemoizedSentinel) {",
" local = Subtype_Factory.newInstance();",
" subtype = DoubleCheck.reentrantCheck(subtype, local);",
" }",
" }",
" }",
" return (Object) local;",
" }",
"",
" @Override",
" public Supertype supertype() {",
" return (Supertype) subtype();",
" }")
.build());
}
@Test
public void noCast_rawTypes_Provider_get_toInaccessibleType() {
JavaFileObject supertype =
JavaFileObjects.forSourceLines(
"other.Supertype",
"package other;",
"",
"interface Supertype {}");
JavaFileObject subtype =
JavaFileObjects.forSourceLines(
"other.Subtype",
"package other;",
"",
"import javax.inject.Inject;",
"import javax.inject.Singleton;",
"",
"@Singleton",
"class Subtype implements Supertype {",
" @Inject Subtype() {}",
"}");
JavaFileObject usesSupertype =
JavaFileObjects.forSourceLines(
"other.UsesSupertype",
"package other;",
"",
"import javax.inject.Inject;",
"",
"public class UsesSupertype {",
" @Inject UsesSupertype(Supertype supertype) {}",
"}");
JavaFileObject module =
JavaFileObjects.forSourceLines(
"other.SupertypeModule",
"package other;",
"",
"import dagger.Binds;",
"import dagger.Module;",
"",
"@Module",
"public interface SupertypeModule {",
" @Binds Supertype to(Subtype subtype);",
"}");
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.TestComponent",
"package test;",
"",
"import dagger.Component;",
"import javax.inject.Singleton;",
"",
"@Singleton",
"@Component(modules = other.SupertypeModule.class)",
"interface TestComponent {",
" other.UsesSupertype usesSupertype();",
"}");
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(supertype, subtype, usesSupertype, module, component);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
.containsElementsIn(
compilerMode
.javaFileBuilder("test.DaggerTestComponent")
.addLines(
"package test;",
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
DEFAULT_MODE,
" @SuppressWarnings(\"rawtypes\")",
" private Provider subtypeProvider;",
"",
" @Override",
" public UsesSupertype usesSupertype() {",
// can't cast the provider.get() to a type that's not accessible
" return UsesSupertype_Factory.newInstance(subtypeProvider.get());",
" }",
"}")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Object subtype = new MemoizedSentinel();",
"",
" private Object subtype() {",
" Object local = subtype;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
" local = subtype;",
" if (local instanceof MemoizedSentinel) {",
" local = Subtype_Factory.newInstance();",
" subtype = DoubleCheck.reentrantCheck(subtype, local);",
" }",
" }",
" }",
" return (Object) local;",
" }",
"",
" @Override",
" public UsesSupertype usesSupertype() {",
" return UsesSupertype_Factory.newInstance(subtype());",
" }")
.build());
}
@Test
public void castedToRawType() {
JavaFileObject module =
JavaFileObjects.forSourceLines(
"test.TestModule",
"package test;",
"",
"import dagger.Binds;",
"import dagger.Module;",
"import dagger.Provides;",
"import javax.inject.Named;",
"",
"@Module",
"interface TestModule {",
" @Provides",
" static String provideString() { return new String(); }",
"",
" @Binds",
" CharSequence charSequence(String string);",
"",
" @Binds",
" @Named(\"named\")",
" String namedString(String string);",
"}");
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.TestComponent",
"package test;",
"",
"import dagger.Component;",
"import javax.inject.Named;",
"import javax.inject.Provider;",
"",
"@Component(modules = TestModule.class)",
"interface TestComponent {",
" Provider<CharSequence> charSequence();",
"",
" @Named(\"named\") Provider<String> namedString();",
"}");
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(module, component);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
.containsElementsIn(
compilerMode
.javaFileBuilder("test.DaggerTestComponent")
.addLines(
"package test;",
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
DEFAULT_MODE,
" @Override",
" public Provider<CharSequence> charSequence() {",
" return (Provider) TestModule_ProvideStringFactory.create();",
" }",
"",
" @Override",
" public Provider<String> namedString() {",
" return TestModule_ProvideStringFactory.create();",
" }",
"}")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Provider<String> provideStringProvider;",
"",
" private Provider<String> stringProvider() {",
" Object local = provideStringProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
" provideStringProvider = (Provider<String>) local;",
" }",
" return (Provider<String>) local;",
" }",
"",
" @Override",
" public Provider<CharSequence> charSequence() {",
" return (Provider) stringProvider();",
" }",
"",
" @Override",
" public Provider<String> namedString() {",
" return stringProvider();",
" }",
"",
" private final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
" case 0:",
" return (T) TestModule_ProvideStringFactory.provideString();",
" default:",
" throw new AssertionError(id);",
" }",
" }",
" }")
.build());
}
@Test
public void doubleBinds() {
JavaFileObject module =
JavaFileObjects.forSourceLines(
"test.TestModule",
"package test;",
"",
"import dagger.Binds;",
"import dagger.Module;",
"import dagger.Provides;",
"",
"@Module",
"interface TestModule {",
" @Provides",
" static String provideString() { return new String(); }",
"",
" @Binds",
" CharSequence charSequence(String string);",
"",
" @Binds",
" Object object(CharSequence charSequence);",
"}");
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.TestComponent",
"package test;",
"",
"import dagger.Component;",
"import javax.inject.Named;",
"import javax.inject.Provider;",
"",
"@Component(modules = TestModule.class)",
"interface TestComponent {",
" Provider<CharSequence> charSequence();",
" Provider<Object> object();",
"}");
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(module, component);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
.containsElementsIn(
compilerMode
.javaFileBuilder("test.DaggerTestComponent")
.addLines(
"package test;",
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
DEFAULT_MODE,
" @Override",
" public Provider<CharSequence> charSequence() {",
" return (Provider) TestModule_ProvideStringFactory.create();",
" }",
" @Override",
" public Provider<Object> object() {",
" return (Provider) TestModule_ProvideStringFactory.create();",
" }",
"}")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Provider<String> provideStringProvider;",
"",
" private Provider<String> stringProvider() {",
" Object local = provideStringProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
" provideStringProvider = (Provider<String>) local;",
" }",
" return (Provider<String>) local;",
" }",
"",
" @Override",
" public Provider<CharSequence> charSequence() {",
" return (Provider) stringProvider();",
" }",
"",
" @Override",
" public Provider<Object> object() {",
" return (Provider) stringProvider();",
" }",
"",
" private final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
" case 0:",
" return (T) TestModule_ProvideStringFactory.provideString();",
" default:",
" throw new AssertionError(id);",
" }",
" }",
" }")
.build());
}
@Test
public void inlineFactoryOfInacessibleType() {
JavaFileObject supertype =
JavaFileObjects.forSourceLines(
"other.Supertype", "package other;", "", "public interface Supertype {}");
JavaFileObject injectableSubtype =
JavaFileObjects.forSourceLines(
"other.Subtype",
"package other;",
"",
"import javax.inject.Inject;",
"",
"final class Subtype implements Supertype {",
// important: this doesn't have any dependencies and therefore the factory will be able
// to be referenced with an inline Subtype_Factory.create()
" @Inject Subtype() {}",
"}");
JavaFileObject module =
JavaFileObjects.forSourceLines(
"other.TestModule",
"package other;",
"",
"import dagger.Binds;",
"import dagger.Module;",
"",
"@Module",
"public interface TestModule {",
" @Binds Supertype to(Subtype subtype);",
"}");
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.RequestsSubtypeAsProvider",
"package test;",
"",
"import dagger.Component;",
"import javax.inject.Provider;",
"",
"@Component(modules = other.TestModule.class)",
"interface RequestsSubtypeAsProvider {",
" Provider<other.Supertype> supertypeProvider();",
"}");
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(supertype, injectableSubtype, module, component);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerRequestsSubtypeAsProvider")
.containsElementsIn(
compilerMode
.javaFileBuilder("test.DaggerRequestsSubtypeAsProvider")
.addLines(
"package test;",
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerRequestsSubtypeAsProvider",
" implements RequestsSubtypeAsProvider {")
.addLinesIn(
DEFAULT_MODE,
" @Override",
" public Provider<Supertype> supertypeProvider() {",
" return (Provider) Subtype_Factory.create();",
" }",
"}")
.addLinesIn(
FAST_INIT_MODE,
" private volatile Provider subtypeProvider;",
"",
" private Provider subtypeProvider() {",
" Object local = subtypeProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
" subtypeProvider = (Provider) local;",
" }",
" return (Provider) local;",
" }",
"",
" @Override",
" public Provider<Supertype> supertypeProvider() {",
" return subtypeProvider();",
" }",
"",
" private final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
" case 0: return (T) Subtype_Factory.newInstance();",
" default: throw new AssertionError(id);",
" }",
" }",
" }")
.build());
}
@Test
public void providerWhenBindsScopeGreaterThanDependencyScope() {
JavaFileObject module =
JavaFileObjects.forSourceLines(
"test.TestModule",
"package test;",
"",
"import dagger.Binds;",
"import dagger.Module;",
"import dagger.Provides;",
"import dagger.Reusable;",
"import javax.inject.Singleton;",
"",
"@Module",
"public abstract class TestModule {",
" @Reusable",
" @Provides",
" static String provideString() {",
" return \"\";",
" }",
"",
" @Binds",
" @Singleton",
" abstract Object bindString(String str);",
"}");
JavaFileObject component =
JavaFileObjects.forSourceLines(
"test.TestComponent",
"package test;",
"",
"import dagger.Component;",
"import javax.inject.Singleton;",
"import javax.inject.Provider;",
"",
"@Singleton",
"@Component(modules = TestModule.class)",
"interface TestComponent {",
" Provider<Object> object();",
"}");
Compilation compilation = compilerWithOptions(compilerMode.javacopts())
.compile(module, component);
assertThat(compilation).succeeded();
assertThat(compilation)
.generatedSourceFile("test.DaggerTestComponent")
.containsElementsIn(
compilerMode
.javaFileBuilder("test.DaggerTestComponent")
.addLines(
"package test;",
"",
GeneratedLines.generatedAnnotations(),
"final class DaggerTestComponent implements TestComponent {")
.addLinesIn(
DEFAULT_MODE,
" private Provider<String> provideStringProvider;",
" private Provider<Object> bindStringProvider;",
"",
" @SuppressWarnings(\"unchecked\")",
" private void initialize() {",
" this.provideStringProvider =",
" SingleCheck.provider(TestModule_ProvideStringFactory.create());",
" this.bindStringProvider =",
" DoubleCheck.provider((Provider) provideStringProvider);",
" }",
"",
" @Override",
" public Provider<Object> object() {",
" return bindStringProvider;",
" }",
"}")
.addLinesIn(
FAST_INIT_MODE,
" private volatile String string;",
" private volatile Object object = new MemoizedSentinel();",
" private volatile Provider<Object> bindStringProvider;",
"",
" private String string() {",
" Object local = string;",
" if (local == null) {",
" local = TestModule_ProvideStringFactory.provideString();",
" string = (String) local;",
" }",
" return (String) local;",
" }",
"",
" private Object object2() {",
" Object local = object;",
" if (local instanceof MemoizedSentinel) {",
" synchronized (local) {",
" local = object;",
" if (local instanceof MemoizedSentinel) {",
" local = string();",
" object = DoubleCheck.reentrantCheck(object, local);",
" }",
" }",
" }",
" return (Object) local;",
" }",
"",
" @Override",
" public Provider<Object> object() {",
" Object local = bindStringProvider;",
" if (local == null) {",
" local = new SwitchingProvider<>(0);",
" bindStringProvider = (Provider<Object>) local;",
" }",
" return (Provider<Object>) local;",
" }",
"",
" private final class SwitchingProvider<T> implements Provider<T> {",
" @SuppressWarnings(\"unchecked\")",
" @Override",
" public T get() {",
" switch (id) {",
" case 0: return (T) DaggerTestComponent.this.object2();",
" default: throw new AssertionError(id);",
" }",
" }",
" }")
.build());
}
private CompilationSubject assertThatCompilationWithModule(JavaFileObject module) {
Compilation compilation =
compilerWithOptions(compilerMode.javacopts())
.compile(
module,
COMPONENT,
QUALIFIER,
REGULAR_SCOPED,
REUSABLE_SCOPED,
UNSCOPED);
assertThat(compilation).succeeded();
return assertThat(compilation);
}
}