blob: 7c059d9c100d19d66d42b1b406033412f5e1f49b [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 dagger.internal.codegen.GeneratedComponentModel.FieldSpecKind.PRIVATE_METHOD_SCOPED_FIELD;
import static javax.lang.model.element.Modifier.PRIVATE;
import static javax.lang.model.element.Modifier.VOLATILE;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.TypeName;
import dagger.internal.DoubleCheck;
import dagger.internal.MemoizedSentinel;
/**
* Defines a method body and return type for double checked locking of the given {@link
* BindingExpression}.
*/
final class DoubleCheckedMethodImplementation extends BindingMethodImplementation {
private final GeneratedComponentModel generatedComponentModel;
private final ContributionBinding binding;
private final Supplier<String> fieldName = Suppliers.memoize(this::createField);
DoubleCheckedMethodImplementation(
ResolvedBindings resolvedBindings,
BindingRequest request,
BindingExpression bindingExpression,
DaggerTypes types,
GeneratedComponentModel generatedComponentModel) {
super(resolvedBindings, request, bindingExpression, generatedComponentModel.name(), types);
this.generatedComponentModel = generatedComponentModel;
this.binding = resolvedBindings.contributionBinding();
}
@Override
CodeBlock body() {
String fieldExpression = fieldName.get().equals("local") ? "this.local" : fieldName.get();
return CodeBlock.builder()
.addStatement("$T local = $L", TypeName.OBJECT, fieldExpression)
.beginControlFlow("if (local instanceof $T)", MemoizedSentinel.class)
.beginControlFlow("synchronized (local)")
.addStatement("local = $L", fieldExpression)
.beginControlFlow("if (local instanceof $T)", MemoizedSentinel.class)
.addStatement("local = $L", simpleBindingExpression())
.addStatement("$1L = $2T.reentrantCheck($1L, local)", fieldExpression, DoubleCheck.class)
.endControlFlow()
.endControlFlow()
.endControlFlow()
.addStatement("return ($T) local", returnType())
.build();
}
private String createField() {
String name = generatedComponentModel.getUniqueFieldName(BindingVariableNamer.name(binding));
generatedComponentModel.addField(
PRIVATE_METHOD_SCOPED_FIELD,
FieldSpec.builder(TypeName.OBJECT, name, PRIVATE, VOLATILE)
.initializer("new $T()", MemoizedSentinel.class)
.build());
return name;
}
}