/** If {@link #bindingElement()} is a method that returns a primitive type, returns that type. */ Optional<TypeMirror> contributedPrimitiveType() { return bindingElement() .filter(bindingElement -> bindingElement instanceof ExecutableElement) .map(bindingElement -> MoreElements.asExecutable(bindingElement).getReturnType()) .filter(type -> type.getKind().isPrimitive()); }
@Override public String visitVariableAsParameter(VariableElement parameter, Void aVoid) { ExecutableElement methodOrConstructor = asExecutable(parameter.getEnclosingElement()); return enclosingTypeAndMemberName(methodOrConstructor) .append('(') .append( formatArgumentInList( methodOrConstructor.getParameters().indexOf(parameter), methodOrConstructor.getParameters().size(), parameter.getSimpleName())) .append(')') .toString(); }
@Override public Set<Element> process( SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) { ImmutableSet.Builder<Element> deferredElements = ImmutableSet.builder(); elementsByAnnotation .entries() .forEach( entry -> { try { validateMethod(entry.getKey(), MoreElements.asExecutable(entry.getValue())); } catch (TypeNotPresentException e) { deferredElements.add(entry.getValue()); } }); return deferredElements.build(); }
/** * Returns the {@link ClassName} in which {@link #mapKeyFactoryMethod(ContributionBinding, * DaggerTypes, DaggerElements)} is generated. */ static ClassName mapKeyProxyClassName(ContributionBinding binding) { return elementBasedClassName( MoreElements.asExecutable(binding.bindingElement().get()), "MapKey"); }
private boolean shouldBeInjected( Element injectionSite, SetMultimap<String, ExecutableElement> overriddenMethodMap) { if (!isAnnotationPresent(injectionSite, Inject.class) || injectionSite.getModifiers().contains(PRIVATE) || injectionSite.getModifiers().contains(STATIC)) { return false; } if (injectionSite.getKind().isField()) { // Inject all fields (self and ancestors) return true; } // For each method with the same name belonging to any descendant class, return false if any // method has already overridden the injectionSite method. To decrease the number of methods // that are checked, we store the already injected methods in a SetMultimap and only // check the methods with the same name. ExecutableElement injectionSiteMethod = MoreElements.asExecutable(injectionSite); TypeElement injectionSiteType = MoreElements.asType(injectionSite.getEnclosingElement()); for (ExecutableElement method : overriddenMethodMap.get(injectionSiteMethod.getSimpleName().toString())) { if (elements.overrides(method, injectionSiteMethod, injectionSiteType)) { return false; } } return true; }
MoreElements.asExecutable(injectionSite.element()); overriddenMethodMap.put( injectionSiteMethod.getSimpleName().toString(), injectionSiteMethod);
/** * Returns {@code true} if injecting an instance of {@code binding} from {@code callingPackage} * requires the use of an injection method. */ static boolean requiresInjectionMethod( ProvisionBinding binding, ImmutableList<Expression> arguments, CompilerOptions compilerOptions, String callingPackage, DaggerTypes types) { ExecutableElement method = MoreElements.asExecutable(binding.bindingElement().get()); return !binding.injectionSites().isEmpty() || binding.shouldCheckForNull(compilerOptions) || !isElementAccessibleFrom(method, callingPackage) || !areParametersAssignable(method, arguments, types) // This check should be removable once we drop support for -source 7 || method.getParameters().stream() .map(VariableElement::asType) .anyMatch(type -> !isRawTypeAccessible(type, callingPackage)); }
@Override public String format(BindingDeclaration bindingDeclaration) { if (bindingDeclaration instanceof SubcomponentDeclaration) { return formatSubcomponentDeclaration((SubcomponentDeclaration) bindingDeclaration); } if (bindingDeclaration.bindingElement().isPresent()) { 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); } } return String.format( "Dagger-generated binding for %s", stripCommonTypePrefixes(bindingDeclaration.key().toString())); }
/** * Returns the generated factory or members injector name for a binding. */ static ClassName generatedClassNameForBinding(Binding binding) { switch (binding.bindingType()) { case PROVISION: case PRODUCTION: ContributionBinding contribution = (ContributionBinding) binding; switch (contribution.kind()) { case INJECTION: case PROVISION: case PRODUCTION: return elementBasedClassName( MoreElements.asExecutable(binding.bindingElement().get()), "Factory"); default: throw new AssertionError(); } case MEMBERS_INJECTION: return membersInjectorNameForType( ((MembersInjectionBinding) binding).membersInjectedType()); default: throw new AssertionError(); } }
message.append( methodSignatureFormatter.format( MoreElements.asExecutable(binding.bindingElement().get()))); break;
/** * Returns a method that invokes the binding's {@linkplain ProvisionBinding#bindingElement() * constructor} and injects the instance's members. */ static InjectionMethod create( ProvisionBinding binding, CompilerOptions compilerOptions, DaggerElements elements) { ClassName proxyEnclosingClass = generatedClassNameForBinding(binding); ExecutableElement element = MoreElements.asExecutable(binding.bindingElement().get()); switch (element.getKind()) { case CONSTRUCTOR: return constructorProxy(proxyEnclosingClass, element, elements); case METHOD: return methodProxy( proxyEnclosingClass, element, methodName(element), ReceiverAccessibility.IGNORE, CheckNotNullPolicy.get(binding, compilerOptions), elements); default: throw new AssertionError(element); } }
private Expression invokeMethod( Function<DependencyRequest, CodeBlock> argumentsFunction, ClassName requestingClass) { // TODO(dpb): align this with the contents of InlineMethods.create CodeBlock arguments = provisionBinding.dependencies().stream() .map(argumentsFunction) .collect(toParametersCodeBlock()); ExecutableElement method = asExecutable(provisionBinding.bindingElement().get()); CodeBlock invocation; switch (method.getKind()) { case CONSTRUCTOR: invocation = CodeBlock.of("new $T($L)", constructorTypeName(requestingClass), arguments); break; case METHOD: CodeBlock module = moduleReference(requestingClass) .orElse(CodeBlock.of("$T", provisionBinding.bindingTypeElement().get())); invocation = CodeBlock.of("$L.$L($L)", module, method.getSimpleName(), arguments); break; default: throw new IllegalStateException(); } return Expression.create(simpleMethodReturnType(), invocation); }
/** * When a type has an inaccessible member from a supertype (e.g. an @Inject field in a parent * that's in a different package), a method in the supertype's package must be generated to give * the subclass's members injector a way to inject it. Each potentially inaccessible member * receives its own method, as the subclass may need to inject them in a different order from * the parent class. */ static InjectionMethod create(InjectionSite injectionSite, DaggerElements elements) { String methodName = methodName(injectionSite); ClassName proxyEnclosingClass = membersInjectorNameForType( MoreElements.asType(injectionSite.element().getEnclosingElement())); switch (injectionSite.kind()) { case METHOD: return methodProxy( proxyEnclosingClass, MoreElements.asExecutable(injectionSite.element()), methodName, ReceiverAccessibility.CAST_IF_NOT_PUBLIC, CheckNotNullPolicy.IGNORE, elements); case FIELD: return fieldProxy( proxyEnclosingClass, MoreElements.asVariable(injectionSite.element()), methodName, elements); default: throw new AssertionError(injectionSite); } }