Skip to content

Commit

Permalink
Add compiler option to append the stacktrace to deferred error messages.
Browse files Browse the repository at this point in the history
RELNOTES=N/A
PiperOrigin-RevId: 427895198
  • Loading branch information
bcorso authored and Dagger Team committed Feb 11, 2022
1 parent 77ac249 commit cbae8a6
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 9 deletions.
13 changes: 11 additions & 2 deletions java/dagger/internal/codegen/compileroption/CompilerOptions.java
Expand Up @@ -84,6 +84,15 @@ public final boolean doCheckForNulls() {

public abstract Diagnostic.Kind staticMemberValidationKind();

/**
* Returns {@code true} if the stacktrace should be included in the deferred error message.
*
* <p>The default for this option is {@code false}. The stacktrace is mostly useful for special
* debugging purposes to gather more information about where the exception was thrown from within
* Dagger's own processors.
*/
public abstract boolean includeStacktraceWithDeferredErrorMessages();

/**
* If {@code true}, Dagger will generate factories and components even if some members-injected
* types have {@code private} or {@code static} {@code @Inject}-annotated members.
Expand Down Expand Up @@ -142,8 +151,8 @@ public final boolean doCheckForNulls() {
* (i.e. versions less than or equal to 2.40.5). However, we will remove this option in a future
* version of Dagger.
*
* <p>Warning:Disabling this option means that Dagger may miss a scope or qualifier on a
* binding, leading to a (wrong) unscoped binding or a (wrong) unqualified binding, respectively.
* <p>Warning:Disabling this option means that Dagger may miss a scope or qualifier on a binding,
* leading to a (wrong) unscoped binding or a (wrong) unqualified binding, respectively.
*/
public abstract boolean strictSuperficialValidation();

Expand Down
Expand Up @@ -30,6 +30,7 @@
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FLOATING_BINDS_METHODS;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.FORMAT_GENERATED_SOURCE;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.PLUGINS_VISIT_FULL_BINDING_GRAPHS;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_MULTIBINDING_VALIDATION;
import static dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions.Feature.STRICT_SUPERFICIAL_VALIDATION;
Expand Down Expand Up @@ -159,6 +160,11 @@ public Diagnostic.Kind staticMemberValidationKind() {
return diagnosticKind(STATIC_MEMBER_VALIDATION);
}

@Override
public boolean includeStacktraceWithDeferredErrorMessages() {
return isEnabled(INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES);
}

@Override
public boolean ignorePrivateAndStaticInjectionForComponent() {
return isEnabled(IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT);
Expand Down Expand Up @@ -318,6 +324,8 @@ enum Feature implements EnumOption<FeatureStatus> {

WARN_IF_INJECTION_FACTORY_NOT_GENERATED_UPSTREAM,

INCLUDE_STACKTRACE_WITH_DEFERRED_ERROR_MESSAGES,

IGNORE_PRIVATE_AND_STATIC_INJECTION_FOR_COMPONENT,

EXPERIMENTAL_AHEAD_OF_TIME_SUBCOMPONENTS,
Expand Down
Expand Up @@ -71,6 +71,11 @@ public Diagnostic.Kind staticMemberValidationKind() {
return NOTE;
}

@Override
public boolean includeStacktraceWithDeferredErrorMessages() {
return false;
}

@Override
public boolean ignorePrivateAndStaticInjectionForComponent() {
return false;
Expand Down
Expand Up @@ -17,6 +17,7 @@
package dagger.internal.codegen.validation;

import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Throwables.getStackTraceAsString;
import static com.google.common.collect.Sets.difference;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableMap;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
Expand All @@ -32,6 +33,7 @@
import com.google.common.collect.Maps;
import com.squareup.javapoet.ClassName;
import dagger.internal.codegen.base.DaggerSuperficialValidation.ValidationException;
import dagger.internal.codegen.compileroption.CompilerOptions;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand All @@ -46,6 +48,7 @@ public abstract class TypeCheckingProcessingStep<E extends XElement> implements

private final List<String> lastDeferredErrorMessages = new ArrayList<>();
@Inject XMessager messager;
@Inject CompilerOptions compilerOptions;
@Inject SuperficialValidator superficialValidator;

@Override
Expand Down Expand Up @@ -78,19 +81,17 @@ public ImmutableSet<XElement> process(
// TODO(bcorso): We should be able to remove this once we replace all calls to
// SuperficialValidation with DaggerSuperficialValidation.
deferredElements.add(element);
lastDeferredErrorMessages.add(typeNotPresentErrorMessage(element, e));
cacheErrorMessage(typeNotPresentErrorMessage(element, e), e);
} catch (ValidationException.UnexpectedException unexpectedException) {
// Rethrow since the exception was created from an unexpected throwable so
// deferring to another round is unlikely to help.
throw unexpectedException;
} catch (ValidationException.KnownErrorType validationException) {
} catch (ValidationException.KnownErrorType e) {
deferredElements.add(element);
lastDeferredErrorMessages.add(
knownErrorTypeErrorMessage(element, validationException));
} catch (ValidationException.UnknownErrorType validationException) {
cacheErrorMessage(knownErrorTypeErrorMessage(element, e), e);
} catch (ValidationException.UnknownErrorType e) {
deferredElements.add(element);
lastDeferredErrorMessages.add(
unknownErrorTypeErrorMessage(element, validationException));
cacheErrorMessage(unknownErrorTypeErrorMessage(element, e), e);
}
});
return deferredElements.build();
Expand All @@ -105,6 +106,13 @@ public void processOver(
lastDeferredErrorMessages.clear();
}

private void cacheErrorMessage(String errorMessage, Exception exception) {
lastDeferredErrorMessages.add(
compilerOptions.includeStacktraceWithDeferredErrorMessages()
? String.format("%s\n\n%s", errorMessage, getStackTraceAsString(exception))
: errorMessage);
}

private String typeNotPresentErrorMessage(XElement element, TypeNotPresentException exception) {
return String.format(
"%1$s was unable to process '%2$s' because '%3$s' could not be resolved."
Expand Down
23 changes: 23 additions & 0 deletions javatests/dagger/internal/codegen/UnresolvableDependencyTest.java
Expand Up @@ -16,8 +16,11 @@

package dagger.internal.codegen;

import static com.google.common.truth.Truth.assertThat;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static dagger.internal.codegen.Compilers.compilerWithOptions;
import static dagger.internal.codegen.Compilers.daggerCompiler;
import static java.util.stream.Collectors.joining;

import com.google.testing.compile.Compilation;
import com.google.testing.compile.JavaFileObjects;
Expand Down Expand Up @@ -86,6 +89,26 @@ public void referencesUnresolvableDependency() {
assertThat(compilation).hadErrorContaining(
"ComponentProcessingStep was unable to process 'test.FooComponent' because "
+ "'UnresolvableDependency' could not be resolved." + trace);

// Only include a minimal portion of the stacktrace to minimize breaking tests due to refactors.
String stacktraceErrorMessage =
"dagger.internal.codegen.base"
+ ".DaggerSuperficialValidation$ValidationException$KnownErrorType";

// Check that the stacktrace is not included in the error message by default.
assertThat(
compilation.errors().stream()
.map(error -> error.getMessage(null))
.collect(joining("\n")))
.doesNotContain(stacktraceErrorMessage);

// Recompile with the option enabled and check that the stacktrace is now included
compilation =
compilerWithOptions("-Adagger.includeStacktraceWithDeferredErrorMessages=ENABLED")
.compile(fooComponent, foo, bar);
assertThat(compilation).failed();
assertThat(compilation).hadErrorCount(3);
assertThat(compilation).hadErrorContaining(stacktraceErrorMessage);
}

@Test
Expand Down

0 comments on commit cbae8a6

Please sign in to comment.