dagger.internal.codegen.BindingDeclarationFormatter.java Source code

Java tutorial

Introduction

Here is the source code for dagger.internal.codegen.BindingDeclarationFormatter.java

Source

/*
 * Copyright (C) 2015 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.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Sets.immutableEnumSet;
import static dagger.internal.codegen.ConfigurationAnnotations.getModuleSubcomponents;
import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_RELEASABLE_REFERENCE_MANAGER;
import static dagger.internal.codegen.ContributionBinding.Kind.SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS;
import static dagger.internal.codegen.ErrorMessages.stripCommonTypePrefixes;
import static dagger.internal.codegen.MoreAnnotationMirrors.simpleName;
import static javax.lang.model.type.TypeKind.DECLARED;
import static javax.lang.model.type.TypeKind.EXECUTABLE;

import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import javax.lang.model.element.Element;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;

/**
 * Formats a {@link BindingDeclaration} into a {@link String} suitable for use in error messages.
 */
final class BindingDeclarationFormatter extends Formatter<BindingDeclaration> {
    private static final ImmutableSet<TypeKind> FORMATTABLE_ELEMENT_TYPE_KINDS = immutableEnumSet(EXECUTABLE,
            DECLARED);

    private static final ImmutableSet<ContributionBinding.Kind> FORMATTABLE_ELEMENTLESS_BINDING_KINDS = immutableEnumSet(
            SYNTHETIC_RELEASABLE_REFERENCE_MANAGER, SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS);

    private final MethodSignatureFormatter methodSignatureFormatter;
    private final KeyFormatter keyFormatter;

    BindingDeclarationFormatter(MethodSignatureFormatter methodSignatureFormatter, KeyFormatter keyFormatter) {
        this.methodSignatureFormatter = methodSignatureFormatter;
        this.keyFormatter = keyFormatter;
    }

    /**
     * Returns {@code true} for declarations that this formatter can format. Specifically:
     *
     * <ul>
     * <li>Those with {@linkplain BindingDeclaration#bindingElement() binding elements} that are
     *     methods, constructors, or types.
     * <li>{@link ContributionBinding.Kind#SYNTHETIC_RELEASABLE_REFERENCE_MANAGER} bindings.
     * <li>{@link ContributionBinding.Kind#SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS} bindings.
     * </ul>
     */
    boolean canFormat(BindingDeclaration bindingDeclaration) {
        if (bindingDeclaration instanceof SubcomponentDeclaration) {
            return true;
        }
        if (bindingDeclaration.bindingElement().isPresent()) {
            return FORMATTABLE_ELEMENT_TYPE_KINDS
                    .contains(bindingDeclaration.bindingElement().get().asType().getKind());
        }
        if (bindingDeclaration instanceof ContributionBinding) {
            ContributionBinding contributionBinding = (ContributionBinding) bindingDeclaration;
            return FORMATTABLE_ELEMENTLESS_BINDING_KINDS.contains(contributionBinding.bindingKind());
        }
        return false;
    }

    @Override
    public String format(BindingDeclaration bindingDeclaration) {
        if (bindingDeclaration instanceof SubcomponentDeclaration) {
            return formatSubcomponentDeclaration((SubcomponentDeclaration) bindingDeclaration);
        }

        if (bindingDeclaration instanceof ContributionBinding) {
            ContributionBinding binding = (ContributionBinding) bindingDeclaration;
            switch (binding.bindingKind()) {
            case SYNTHETIC_RELEASABLE_REFERENCE_MANAGER:
                return String.format("binding for %s from the scope declaration",
                        stripCommonTypePrefixes(keyFormatter.format(binding.key())));
            case SYNTHETIC_RELEASABLE_REFERENCE_MANAGERS:
                return String.format("Dagger-generated binding for %s",
                        stripCommonTypePrefixes(keyFormatter.format(binding.key())));
            default:
                break;
            }
        }

        checkArgument(bindingDeclaration.bindingElement().isPresent(),
                "Cannot format bindings without source elements: %s", bindingDeclaration);

        Element bindingElement = bindingDeclaration.bindingElement().get();
        switch (bindingElement.asType().getKind()) {
        case EXECUTABLE:
            return methodSignatureFormatter.format(MoreElements.asExecutable(bindingElement),
                    bindingDeclaration.contributingModule().map(module -> MoreTypes.asDeclared(module.asType())));
        case DECLARED:
            return stripCommonTypePrefixes(bindingElement.asType().toString());
        default:
            throw new IllegalArgumentException("Formatting unsupported for element: " + bindingElement);
        }
    }

    private String formatSubcomponentDeclaration(SubcomponentDeclaration subcomponentDeclaration) {
        ImmutableList<TypeMirror> moduleSubcomponents = getModuleSubcomponents(
                subcomponentDeclaration.moduleAnnotation());
        int index = Iterables.indexOf(moduleSubcomponents,
                MoreTypes.equivalence().equivalentTo(subcomponentDeclaration.subcomponentType().asType()));
        StringBuilder annotationValue = new StringBuilder();
        if (moduleSubcomponents.size() != 1) {
            annotationValue.append("{");
        }
        annotationValue.append(formatArgumentInList(index, moduleSubcomponents.size(),
                subcomponentDeclaration.subcomponentType().getQualifiedName() + ".class"));
        if (moduleSubcomponents.size() != 1) {
            annotationValue.append("}");
        }

        return String.format("@%s(subcomponents = %s) for %s",
                simpleName(subcomponentDeclaration.moduleAnnotation()), annotationValue,
                subcomponentDeclaration.contributingModule().get());
    }
}