Skip to content

Commit

Permalink
Use Failure for CC problems from the diagnosic (#28968)
Browse files Browse the repository at this point in the history
  • Loading branch information
alllex committed Apr 26, 2024
2 parents 841190b + 70f2748 commit 603d241
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 27 deletions.
Expand Up @@ -773,7 +773,6 @@ class ConfigurationCacheFingerprintWriter(
PropertyProblem(
trace,
StructuredMessage.build(messageBuilder),
null,
documentationSection = documentationSection
)
)
Expand Down
Expand Up @@ -33,8 +33,7 @@ class ConfigurationCacheInjectedClasspathInstrumentationStrategy(
PropertyProblem(
PropertyTrace.Gradle,
StructuredMessage.build { text("support for using a Java agent with TestKit builds is not yet implemented with the configuration cache.") },
null,
DocumentationSection.NotYetImplementedTestKitJavaAgent
documentationSection = DocumentationSection.NotYetImplementedTestKitJavaAgent
)
)
return CachedClasspathTransformer.StandardTransform.BuildLogic
Expand Down
Expand Up @@ -31,6 +31,7 @@ import org.gradle.configurationcache.initialization.ConfigurationCacheStartParam
import org.gradle.initialization.RootBuildLifecycleListener
import org.gradle.internal.InternalBuildAdapter
import org.gradle.internal.event.ListenerManager
import org.gradle.internal.problems.failure.FailureFactory
import org.gradle.internal.service.scopes.Scope
import org.gradle.internal.service.scopes.ServiceScope
import org.gradle.problems.buildtree.ProblemReporter
Expand All @@ -52,9 +53,13 @@ class ConfigurationCacheProblems(
val cacheKey: ConfigurationCacheKey,

private
val listenerManager: ListenerManager
val listenerManager: ListenerManager,

private
val failureFactory: FailureFactory

) : ProblemsListener, ProblemReporter, AutoCloseable {

private
val summarizer = ConfigurationCacheProblemsSummary()

Expand Down Expand Up @@ -129,7 +134,8 @@ class ConfigurationCacheProblems(
}

override fun onError(trace: PropertyTrace, error: Exception, message: StructuredMessageBuilder) {
onProblem(PropertyProblem(trace, StructuredMessage.build(message), error))
val failure = failureFactory.create(error)
onProblem(PropertyProblem(trace, StructuredMessage.build(message), error, failure))
}
}
}
Expand Down Expand Up @@ -192,6 +198,7 @@ class ConfigurationCacheProblems(
val log: (String) -> Unit = if (logReportAsInfo) logger::info else logger::warn
log(summary.textForConsole(cacheActionText, htmlReportFile))
}

else -> validationFailures.accept(failure)
}
}
Expand Down
Expand Up @@ -27,7 +27,6 @@ import org.gradle.internal.hash.HashCode
import org.gradle.internal.hash.Hashing
import org.gradle.internal.hash.HashingOutputStream
import org.gradle.internal.problems.failure.Failure
import org.gradle.internal.problems.failure.FailureFactory
import org.gradle.internal.service.scopes.Scope
import org.gradle.internal.service.scopes.ServiceScope
import java.io.Closeable
Expand All @@ -42,8 +41,7 @@ import kotlin.contracts.contract
class ConfigurationCacheReport(
executorFactory: ExecutorFactory,
temporaryFileProvider: TemporaryFileProvider,
internalOptions: InternalOptions,
private val failureFactory: FailureFactory
internalOptions: InternalOptions
) : Closeable {

companion object {
Expand Down Expand Up @@ -229,7 +227,7 @@ class ConfigurationCacheReport(

private
fun decorateProblem(problem: PropertyProblem, severity: ProblemSeverity): DecoratedPropertyProblem {
val failure = problem.exception?.toFailure()
val failure = problem.stackTracingFailure
return DecoratedPropertyProblem(
problem.trace,
decorateMessage(problem, failure),
Expand All @@ -238,9 +236,6 @@ class ConfigurationCacheReport(
)
}

private
fun Throwable.toFailure() = failureFactory.create(this)

private
fun decoratedFailureFor(failure: Failure?, severity: ProblemSeverity): DecoratedFailure? {
return when {
Expand Down
Expand Up @@ -75,19 +75,24 @@ class FailureDecorator {

private
fun exceptionSummaryFor(failure: Failure): StructuredMessage? {
failure.stackTrace.forEachIndexed { index, element ->
if (failure.getStackTraceRelevance(index).isUserCode()) {
return exceptionSummaryFrom(element)
return failure.findFirstUserCode()?.let(::exceptionSummaryFrom)
}

private
fun Failure.findFirstUserCode(): StackTraceElement? {
stackTrace.forEachIndexed { index, element ->
if (getStackTraceRelevance(index).isUserCode()) {
return element
}
}

return null
}

private
fun exceptionSummaryFrom(elem: StackTraceElement) = StructuredMessage.build {
fun exceptionSummaryFrom(frame: StackTraceElement) = StructuredMessage.build {
text("at ")
reference(elem.toString())
reference(frame.toString())
}

private
Expand Down
Expand Up @@ -36,8 +36,9 @@ class DefaultProblemFactory(
locationForCaller(consumer, userCodeContext.current()?.source)

override fun problem(message: StructuredMessage, exception: Throwable?, documentationSection: DocumentationSection?): PropertyProblem {
val trace = locationForCaller(null, problemStream.forCurrentCaller(exception))
return PropertyProblem(trace, message, exception, documentationSection)
val diagnostics = problemStream.forCurrentCaller(exception)
val trace = locationForCaller(null, diagnostics)
return PropertyProblem(trace, message, exception, diagnostics.failure, documentationSection)
}

override fun problem(consumer: String?, messageBuilder: StructuredMessage.Builder.() -> Unit): ProblemFactory.Builder {
Expand Down Expand Up @@ -73,13 +74,14 @@ class DefaultProblemFactory(
}

override fun build(): PropertyProblem {
val exceptionMessage = exceptionMessage
val diagnostics = if (exceptionMessage == null) {
problemStream.forCurrentCaller()
} else {
problemStream.forCurrentCaller(Supplier { InvalidUserCodeException(exceptionMessage!!) })
problemStream.forCurrentCaller(Supplier { InvalidUserCodeException(exceptionMessage) })
}
val location = locationMapper(locationForCaller(consumer, diagnostics))
return PropertyProblem(location, message, diagnostics.exception, documentationSection)
return PropertyProblem(location, message, diagnostics.exception, diagnostics.failure, documentationSection)
}
}
}
Expand Down
Expand Up @@ -17,6 +17,7 @@
package org.gradle.configurationcache.problems

import org.gradle.internal.DisplayName
import org.gradle.internal.problems.failure.Failure
import kotlin.reflect.KClass


Expand All @@ -27,6 +28,11 @@ data class PropertyProblem internal constructor(
val trace: PropertyTrace,
val message: StructuredMessage,
val exception: Throwable? = null,
/**
* A failure containing stack tracing information.
* The failure may be synthetic when the cause of the problem was not an exception.
*/
val stackTracingFailure: Failure? = null,
val documentationSection: DocumentationSection? = null
)

Expand Down Expand Up @@ -175,41 +181,49 @@ sealed class PropertyTrace {
is Gradle -> {
append("Gradle runtime")
}

is Property -> {
append(trace.kind)
append(" ")
quoted(trace.name)
append(" of ")
}

is SystemProperty -> {
append("system property ")
quoted(trace.name)
append(" set at ")
}

is Bean -> {
quoted(trace.type.name)
append(" bean found in ")
}

is Task -> {
append("task ")
quoted(trace.path)
append(" of type ")
quoted(trace.type.name)
}

is BuildLogic -> {
append(trace.source.displayName)
trace.lineNumber?.let {
append(": line ")
append(it)
}
}

is BuildLogicClass -> {
append("class ")
quoted(trace.name)
}

is Unknown -> {
append("unknown location")
}

is Project -> {
append("project ")
quoted(trace.path)
Expand Down
Expand Up @@ -31,11 +31,10 @@ import kotlin.reflect.KClass

fun IsolateContext.logPropertyProblem(
action: String,
exception: Throwable? = null,
documentationSection: DocumentationSection? = null,
message: StructuredMessageBuilder
) {
logPropertyProblem(action, PropertyProblem(trace, build(message), exception, documentationSection))
logPropertyProblem(action, PropertyProblem(trace, build(message), documentationSection = documentationSection))
}


Expand Down Expand Up @@ -108,15 +107,15 @@ fun IsolateContext.logNotImplemented(feature: String, documentationSection: Docu
build {
text("support for $feature is not yet implemented with the configuration cache.")
},
null, documentationSection
documentationSection = documentationSection
)
)
}


private
fun IsolateContext.logPropertyProblem(documentationSection: DocumentationSection? = null, message: StructuredMessageBuilder) {
val problem = PropertyProblem(trace, build(message), null, documentationSection)
val problem = PropertyProblem(trace, build(message), documentationSection = documentationSection)
logPropertyProblem("serialize", problem)
}

Expand Down
Expand Up @@ -106,15 +106,16 @@ private ProblemDiagnostics locationFromStackTrace(@Nullable Throwable throwable,
}

List<StackTraceElement> stackTrace = Collections.emptyList();
Failure stackTracingFailure = null;
Location location = null;
if (throwable != null) {
stackTrace = transformer.transform(throwable.getStackTrace());
Failure stackTracingFailure = failureFactory.create(throwable);
stackTracingFailure = failureFactory.create(throwable);
location = locationAnalyzer.locationForUsage(stackTracingFailure, fromException);
}

UserCodeSource source = applicationContext != null ? applicationContext.getSource() : null;
return new DefaultProblemDiagnostics(keepException ? throwable : null, stackTrace, location, source);
return new DefaultProblemDiagnostics(stackTracingFailure, keepException ? throwable : null, stackTrace, location, source);
}

@NonNullApi
Expand Down Expand Up @@ -160,23 +161,32 @@ private Throwable getImplicitThrowable(Supplier<? extends Throwable> factory) {
}

private static class DefaultProblemDiagnostics implements ProblemDiagnostics {
private final Failure failure;
private final Throwable exception;
private final List<StackTraceElement> stackTrace;
private final Location location;
private final UserCodeSource source;

public DefaultProblemDiagnostics(
@Nullable Failure stackTracingFailure,
@Nullable Throwable exception,
List<StackTraceElement> stackTrace,
@Nullable Location location,
@Nullable UserCodeSource source
) {
this.failure = stackTracingFailure;
this.exception = exception;
this.stackTrace = stackTrace;
this.location = location;
this.source = source;
}

@Nullable
@Override
public Failure getFailure() {
return failure;
}

@Nullable
@Override
public Throwable getException() {
Expand Down
Expand Up @@ -18,6 +18,7 @@

import com.google.common.base.Supplier;
import org.gradle.internal.code.UserCodeSource;
import org.gradle.internal.problems.failure.Failure;
import org.gradle.problems.Location;
import org.gradle.problems.ProblemDiagnostics;
import org.gradle.problems.buildtree.ProblemDiagnosticsFactory;
Expand All @@ -29,6 +30,12 @@

public class NoOpProblemDiagnosticsFactory implements ProblemDiagnosticsFactory {
public static final ProblemDiagnostics EMPTY_DIAGNOSTICS = new ProblemDiagnostics() {
@Nullable
@Override
public Failure getFailure() {
return null;
}

@Nullable
@Override
public Throwable getException() {
Expand Down
Expand Up @@ -17,6 +17,7 @@
package org.gradle.problems;

import org.gradle.internal.code.UserCodeSource;
import org.gradle.internal.problems.failure.Failure;

import javax.annotation.Nullable;
import java.util.List;
Expand All @@ -25,6 +26,19 @@
* An immutable set of diagnostic information for a problem.
*/
public interface ProblemDiagnostics {

/**
* A stack tracing failure associated with the problem.
* <p>
* Usually, if the problem was caused by an exception, the failure would correspond to that exception.
* However, problems that are registered explicitly (e.g. deprecation warnings) will not have an associated exception.
* In this case, the failure can be synthetic to provide the stack trace for the problem origin.
* <p>
* The failure can also be omitted due to limits. Its absence does not mean there was no exception causing the problem.
*/
@Nullable
Failure getFailure();

/**
* Returns an exception that can be thrown when this problem should result in an error.
*
Expand Down

0 comments on commit 603d241

Please sign in to comment.