Skip to content

Commit

Permalink
Dependency resolving process in graph build errors (#217)
Browse files Browse the repository at this point in the history
  • Loading branch information
Squiry authored Jul 24, 2023
1 parent cd6470e commit af88de2
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import org.slf4j.LoggerFactory;

import javax.annotation.processing.ProcessingEnvironment;
import javax.tools.Diagnostic;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.nio.file.Path;
Expand Down Expand Up @@ -37,11 +36,9 @@ public static synchronized void init(ProcessingEnvironment processingEnv) {
} else if (dir.getFileName().toString().startsWith("generated-")) {
buildDir = dir.getParent();
} else {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Build dir was no detected, there will be no build log for kora");
return;
}
} catch (IOException e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Build dir was no detected, there will be no build log for kora");
return;
}
initLog(processingEnv);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static ProcessingState processProcessing(ProcessingContext ctx, RoundEnvi
return new ProcessingState.Failed(new ProcessingErrorException(
"@KoraApp has no root components, expected at least one component annotated with @Root",
processing.root()
));
), new ArrayDeque<>());
}
var stack = processing.resolutionStack();
frame:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
}
} catch (ProcessingErrorException e) {
log.info("Processing exception", e);
results.put(annotatedClass.getKey(), new ProcessingState.Failed(e));
results.put(annotatedClass.getKey(), new ProcessingState.Failed(e, processingResult.stack()));
} catch (Exception e) {
if (e instanceof FilerException || e.getCause() instanceof FilerException) {
this.processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, e.getMessage());
Expand All @@ -146,6 +146,22 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
}
if (processingResult instanceof ProcessingState.Failed failed) {
failed.detailedException().printError(this.processingEnv);
if (!failed.stack().isEmpty()) {
var i = processingResult.stack().descendingIterator();
var frames = new ArrayList<ProcessingState.ResolutionFrame.Component>();
while (i.hasNext()) {
var frame = i.next();
if (frame instanceof ProcessingState.ResolutionFrame.Component c) {
frames.add(0, c);
} else {
break;
}
}
var chain = frames.stream()
.map(c -> c.declaration().declarationString() + " " + c.dependenciesToFind().get(c.currentDependency()))
.collect(Collectors.joining("\n | \n ^ \n"));
this.processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Dependency resolve process: \n" + chain);
}
}
if (processingResult instanceof ProcessingState.Ok ok) {
try {
Expand Down Expand Up @@ -232,7 +248,7 @@ private ProcessingState.Processing processNone(ProcessingState.None none) {

private ProcessingState parseNone(Element classElement) {
if (classElement.getKind() != ElementKind.INTERFACE) {
return new ProcessingState.Failed(new ProcessingErrorException("@KoraApp is only applicable to interfaces", classElement));
return new ProcessingState.Failed(new ProcessingErrorException("@KoraApp is only applicable to interfaces", classElement), new ArrayDeque<>());
}
try {
var type = (TypeElement) classElement;
Expand Down Expand Up @@ -269,7 +285,7 @@ record Components(List<ComponentDeclaration> templates, List<ComponentDeclaratio
.toList();
return new ProcessingState.None(type, allModules, sourceDescriptors, components.templates, rootSet);
} catch (ProcessingErrorException e) {
return new ProcessingState.Failed(e);
return new ProcessingState.Failed(e, new ArrayDeque<>());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@
import javax.annotation.Nullable;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.Set;
import java.util.*;

public sealed interface ProcessingState {
sealed interface ResolutionFrame {
Expand All @@ -29,7 +26,14 @@ public Component withCurrentDependency(int currentDependency) {
}
}

record None(TypeElement root, List<TypeElement> allModules, List<ComponentDeclaration> sourceDeclarations, List<ComponentDeclaration> templates, List<ComponentDeclaration> rootSet) implements ProcessingState {}
default Deque<ResolutionFrame> stack() {
return this instanceof Processing processing
? processing.resolutionStack
: new ArrayDeque<>();
}

record None(TypeElement root, List<TypeElement> allModules, List<ComponentDeclaration> sourceDeclarations, List<ComponentDeclaration> templates,
List<ComponentDeclaration> rootSet) implements ProcessingState {}

record Processing(TypeElement root, List<TypeElement> allModules, List<ComponentDeclaration> sourceDeclarations, List<ComponentDeclaration> templates, List<ComponentDeclaration> rootSet,
List<ResolvedComponent> resolvedComponents, Deque<ResolutionFrame> resolutionStack) implements ProcessingState {
Expand All @@ -49,5 +53,5 @@ record Ok(TypeElement root, List<TypeElement> allModules, List<ResolvedComponent

record NewRoundRequired(Object source, TypeMirror type, Set<String> tag, Processing processing) implements ProcessingState {}

record Failed(ProcessingErrorException detailedException) implements ProcessingState {}
record Failed(ProcessingErrorException detailedException, Deque<ResolutionFrame> stack) implements ProcessingState {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ default boolean isDefault() {

boolean isInterceptor();

String declarationString();

record FromModuleComponent(TypeMirror type, ModuleDeclaration module, Set<String> tags, ExecutableElement method, List<TypeMirror> methodParameterTypes,
List<TypeMirror> typeVariables, boolean isInterceptor) implements ComponentDeclaration {
@Override
Expand All @@ -38,6 +40,11 @@ public Element source() {
public boolean isDefault() {
return AnnotationUtils.findAnnotation(this.method, CommonClassNames.defaultComponent) != null;
}

@Override
public String declarationString() {
return module.element().getQualifiedName() + "." + method.getSimpleName();
}
}

record AnnotatedComponent(TypeMirror type, TypeElement typeElement, Set<String> tags, ExecutableElement constructor, List<TypeMirror> methodParameterTypes,
Expand All @@ -46,6 +53,11 @@ record AnnotatedComponent(TypeMirror type, TypeElement typeElement, Set<String>
public Element source() {
return this.constructor;
}

@Override
public String declarationString() {
return typeElement.getQualifiedName().toString();
}
}

record DiscoveredAsDependencyComponent(TypeMirror type, TypeElement typeElement, ExecutableElement constructor, Set<String> tags) implements ComponentDeclaration {
Expand All @@ -67,6 +79,11 @@ public boolean isTemplate() {
public boolean isInterceptor() {
return false;
}

@Override
public String declarationString() {
return typeElement.getQualifiedName().toString();
}
}

record FromExtensionComponent(TypeMirror type, ExecutableElement sourceMethod, List<TypeMirror> methodParameterTypes) implements ComponentDeclaration {
Expand All @@ -84,6 +101,11 @@ public Set<String> tags() {
public boolean isInterceptor() {
return false;
}

@Override
public String declarationString() {
return sourceMethod.getEnclosingElement().toString() + "." + sourceMethod.getSimpleName();
}
}

record PromisedProxyComponent(TypeElement typeElement, TypeMirror type, com.squareup.javapoet.ClassName className) implements ComponentDeclaration {
Expand All @@ -110,6 +132,11 @@ public Set<String> tags() {
public boolean isInterceptor() {
return false;
}

@Override
public String declarationString() {
return "<Proxy>";
}
}

record OptionalComponent(TypeMirror type, Set<String> tags) implements ComponentDeclaration {
Expand All @@ -122,6 +149,11 @@ public Element source() {
public boolean isInterceptor() {
return false;
}

@Override
public String declarationString() {
return "<EmptyOptional>";
}
}

static ComponentDeclaration fromModule(ProcessingContext ctx, ModuleDeclaration module, ExecutableElement method) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ void appWithAllOf() throws Throwable {
void unresolvedDependency() {
assertThatThrownBy(() -> testClass(AppWithUnresolvedDependency.class))
.isInstanceOfSatisfying(CompilationErrorException.class, e -> SoftAssertions.assertSoftly(s -> {
s.assertThat(e.getMessage()).isEqualTo("""
s.assertThat(e.getMessage()).startsWith("""
Required dependency type was not found and can't be auto created: ru.tinkoff.kora.kora.app.annotation.processor.app.AppWithUnresolvedDependency.Class3.
Please check class for @Component annotation or that required module with component is plugged in.
Requested at: ru.tinkoff.kora.kora.app.annotation.processor.app.AppWithUnresolvedDependency.class2(ru.tinkoff.kora.kora.app.annotation.processor.app.AppWithUnresolvedDependency.Class3)""");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ object GraphBuilder {
ProcessingErrorException(
"@KoraApp has no root components, expected at least one component annotated with @Root",
p.root
)
),
p.resolutionStack
)
}
var processing = p;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,22 @@ class KoraAppProcessor(
when (processingResult) {
is ProcessingState.Failed -> {
processingResult.exception.printError(kspLogger)
throw processingResult.exception
if (processingResult.resolutionStack.isNotEmpty()) {
val i = processingResult.resolutionStack.descendingIterator()
val frames = ArrayList<ProcessingState.ResolutionFrame.Component>()
while (i.hasNext()) {
val frame = i.next()
if (frame is ProcessingState.ResolutionFrame.Component) {
frames.add(0, frame)
} else {
break
}
}
val chain = frames.joinToString("\n | \n ^ \n") {
it.declaration.declarationString() + " " + it.dependenciesToFind[it.currentDependency]
}
kspLogger.warn("Dependency resolve process: $chain")
}
}

is ProcessingState.NewRoundRequired -> {
Expand Down Expand Up @@ -152,7 +167,7 @@ class KoraAppProcessor(
e.resolving
)
} catch (e: ProcessingErrorException) {
results[actualKey] = declaration to ProcessingState.Failed(e)
results[actualKey] = declaration to ProcessingState.Failed(e, processingResult.stack())
}
}
processedDeclarations.putAll(results)
Expand All @@ -176,7 +191,7 @@ class KoraAppProcessor(

private fun parseNone(declaration: KSClassDeclaration): ProcessingState {
if (declaration.classKind != ClassKind.INTERFACE) {
return ProcessingState.Failed(ProcessingErrorException("@KoraApp is only applicable to interfaces", declaration))
return ProcessingState.Failed(ProcessingErrorException("@KoraApp is only applicable to interfaces", declaration), ArrayDeque())
}
try {
val rootErasure = declaration.asStarProjectedType()
Expand Down Expand Up @@ -237,7 +252,7 @@ class KoraAppProcessor(
}
return ProcessingState.None(declaration, allModules, components, templateComponents, rootSet)
} catch (e: ProcessingErrorException) {
return ProcessingState.Failed(e)
return ProcessingState.Failed(e, ArrayDeque())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ sealed interface ProcessingState {
) : ResolutionFrame
}

fun stack() = if (this is Processing) {
this.resolutionStack
} else {
ArrayDeque()
}

data class None(
val root: KSClassDeclaration,
val allModules: List<KSClassDeclaration>,
Expand All @@ -45,5 +51,5 @@ sealed interface ProcessingState {

data class Ok(val root: KSClassDeclaration, val allModules: List<KSClassDeclaration>, val components: List<ResolvedComponent>) : ProcessingState
data class NewRoundRequired(val source: Any, val type: KSType, val tag: Set<String>, val processing: Processing) : ProcessingState
data class Failed(val exception: ProcessingErrorException) : ProcessingState
data class Failed(val exception: ProcessingErrorException, val resolutionStack: Deque<ResolutionFrame>) : ProcessingState
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ sealed interface ComponentDeclaration {
val source: KSDeclaration
val tags: Set<String>

fun declarationString(): String

fun isTemplate(): Boolean {
for (argument in type.arguments) {
if (argument.hasGenericVariable()) {
Expand All @@ -37,6 +39,8 @@ sealed interface ComponentDeclaration {
val typeVariables: List<KSTypeArgument>
) : ComponentDeclaration {
override val source get() = this.method
override fun declarationString() = module.element.qualifiedName?.asString() + "." + method.simpleName.asString()

override fun isDefault(): Boolean {
return method.findAnnotation(CommonClassNames.defaultComponent) != null
}
Expand All @@ -51,6 +55,7 @@ sealed interface ComponentDeclaration {
val typeVariables: List<KSTypeArgument>
) : ComponentDeclaration {
override val source get() = this.constructor
override fun declarationString() = classDeclaration.qualifiedName?.asString().toString()
}

data class DiscoveredAsDependencyComponent(
Expand All @@ -60,6 +65,7 @@ sealed interface ComponentDeclaration {
override val tags: Set<String>
) : ComponentDeclaration {
override val source get() = this.constructor
override fun declarationString() = classDeclaration.qualifiedName?.asString().toString()
}

data class FromExtensionComponent(
Expand All @@ -70,6 +76,9 @@ sealed interface ComponentDeclaration {
) : ComponentDeclaration {
override val source get() = this.sourceMethod
override val tags get() = setOf<String>()
override fun declarationString(): String {
return sourceMethod.parentDeclaration?.qualifiedName?.asString().toString() + sourceMethod.simpleName.asString()
}

}

Expand All @@ -81,6 +90,7 @@ sealed interface ComponentDeclaration {
) : ComponentDeclaration {
override val source get() = this.classDeclaration
override val tags get() = setOf(CommonClassNames.promisedProxy.canonicalName)
override fun declarationString() = "<Proxy>"
}


Expand All @@ -89,6 +99,7 @@ sealed interface ComponentDeclaration {
override val tags: Set<String>
) : ComponentDeclaration {
override val source get() = type.declaration
override fun declarationString() = "Optional.empty"
}


Expand Down

0 comments on commit af88de2

Please sign in to comment.