From 7a3df6175ec3a0ddab7b08092abcf758d830ac85 Mon Sep 17 00:00:00 2001 From: Ryan Shavell Date: Sat, 31 May 2025 09:38:51 -0400 Subject: [PATCH] [epilogue] Add superclass field & method logging (#7993) --- .../epilogue/processor/ElementHandler.java | 10 +- .../epilogue/processor/LoggerGenerator.java | 105 +-- .../processor/AnnotationProcessorTest.java | 654 ++++++++++++++++-- 3 files changed, 672 insertions(+), 97 deletions(-) diff --git a/epilogue-processor/src/main/java/edu/wpi/first/epilogue/processor/ElementHandler.java b/epilogue-processor/src/main/java/edu/wpi/first/epilogue/processor/ElementHandler.java index c097d59137..d12acb7ecc 100644 --- a/epilogue-processor/src/main/java/edu/wpi/first/epilogue/processor/ElementHandler.java +++ b/epilogue-processor/src/main/java/edu/wpi/first/epilogue/processor/ElementHandler.java @@ -13,7 +13,9 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; /** * Handles logging of fields or methods. An element that passes the {@link #isLoggable(Element)} @@ -126,11 +128,15 @@ public abstract class ElementHandler { } private static String fieldAccess(VariableElement field) { - if (field.getModifiers().contains(Modifier.PRIVATE)) { + if (!field.getModifiers().contains(Modifier.PUBLIC)) { // ((com.example.Foo) $fooField.get(object)) // Extra parentheses so cast evaluates before appended methods // (e.g. when appending .getAsDouble()) - return "((" + field.asType() + ") $" + field.getSimpleName() + ".get(object))"; + TypeMirror type = field.asType(); + if (type.getKind() == TypeKind.TYPEVAR) { + type = ((TypeVariable) type).getUpperBound(); + } + return "((" + type.toString() + ") $" + field.getSimpleName() + ".get(object))"; } else { // object.fooField return "object." + field.getSimpleName(); diff --git a/epilogue-processor/src/main/java/edu/wpi/first/epilogue/processor/LoggerGenerator.java b/epilogue-processor/src/main/java/edu/wpi/first/epilogue/processor/LoggerGenerator.java index 496a773095..7fbb82a931 100644 --- a/epilogue-processor/src/main/java/edu/wpi/first/epilogue/processor/LoggerGenerator.java +++ b/epilogue-processor/src/main/java/edu/wpi/first/epilogue/processor/LoggerGenerator.java @@ -114,42 +114,10 @@ public class LoggerGenerator { if (config == null) { config = m_defaultConfig; } - boolean requireExplicitOptIn = config.strategy() == Logged.Strategy.OPT_IN; - Predicate notSkipped = LoggerGenerator::isNotSkipped; - Predicate optedIn = - e -> !requireExplicitOptIn || e.getAnnotation(Logged.class) != null; - - List fieldsToLog; - if (Objects.equals(clazz.getSuperclass().toString(), "java.lang.Record")) { - // Do not log record members - just use the accessor methods - fieldsToLog = List.of(); - } else { - fieldsToLog = - clazz.getEnclosedElements().stream() - .filter(e -> e instanceof VariableElement) - .map(e -> (VariableElement) e) - .filter(notSkipped) - .filter(optedIn) - .filter(e -> !e.getModifiers().contains(Modifier.STATIC)) - .filter(this::isLoggable) - .toList(); - } - - List methodsToLog = - clazz.getEnclosedElements().stream() - .filter(e -> e instanceof ExecutableElement) - .map(e -> (ExecutableElement) e) - .filter(notSkipped) - .filter(optedIn) - .filter(e -> !e.getModifiers().contains(Modifier.STATIC)) - .filter(e -> e.getModifiers().contains(Modifier.PUBLIC)) - .filter(e -> e.getParameters().isEmpty()) - .filter(e -> e.getReceiverType() != null) - .filter(kIsBuiltInJavaMethod.negate()) - .filter(this::isLoggable) - .filter(e -> !isSimpleGetterMethodForLoggedField(e, fieldsToLog)) - .toList(); + List fieldsToLog = new ArrayList<>(); + List methodsToLog = new ArrayList<>(); + collectLoggables(clazz, fieldsToLog, methodsToLog); // Validate no name collisions Map> usedNames = @@ -216,9 +184,9 @@ public class LoggerGenerator { var loggerFile = m_processingEnv.getFiler().createSourceFile(loggerClassName); - var privateFields = - loggableFields.stream().filter(e -> e.getModifiers().contains(Modifier.PRIVATE)).toList(); - boolean requiresVarHandles = !privateFields.isEmpty(); + var varHandleFields = + loggableFields.stream().filter(e -> !e.getModifiers().contains(Modifier.PUBLIC)).toList(); + boolean requiresVarHandles = !varHandleFields.isEmpty(); try (var out = new PrintWriter(loggerFile.openWriter())) { if (packageName != null) { @@ -246,10 +214,10 @@ public class LoggerGenerator { + "> {"); if (requiresVarHandles) { - for (var privateField : privateFields) { + for (var varHandleField : varHandleFields) { // This field needs a VarHandle to access. // Cache it in the class to avoid lookups - out.println(" private static final VarHandle $" + privateField.getSimpleName() + ";"); + out.println(" private static final VarHandle $" + varHandleField.getSimpleName() + ";"); } out.println(); @@ -262,8 +230,8 @@ public class LoggerGenerator { + classReference + ", MethodHandles.lookup());"); - for (var privateField : privateFields) { - var fieldName = privateField.getSimpleName(); + for (var varHandleField : varHandleFields) { + var fieldName = varHandleField.getSimpleName(); out.println( " $" + fieldName @@ -272,7 +240,7 @@ public class LoggerGenerator { + ", \"" + fieldName + "\", " - + m_processingEnv.getTypeUtils().erasure(privateField.asType()) + + m_processingEnv.getTypeUtils().erasure(varHandleField.asType()) + ".class);"); } @@ -347,6 +315,57 @@ public class LoggerGenerator { } } + private void collectLoggables( + TypeElement clazz, List fields, List methods) { + var config = clazz.getAnnotation(Logged.class); + if (config == null) { + config = m_defaultConfig; + } + boolean requireExplicitOptIn = config.strategy() == Logged.Strategy.OPT_IN; + + Predicate notSkipped = LoggerGenerator::isNotSkipped; + Predicate optedIn = + e -> !requireExplicitOptIn || e.getAnnotation(Logged.class) != null; + + List classFields; + if (Objects.equals(clazz.getSuperclass().toString(), "java.lang.Record")) { + // Do not log record members - just use the accessor methods + classFields = List.of(); + } else { + classFields = + clazz.getEnclosedElements().stream() + .filter(e -> e instanceof VariableElement) + .map(e -> (VariableElement) e) + .filter(notSkipped) + .filter(optedIn) + .filter(e -> !e.getModifiers().contains(Modifier.STATIC)) + .filter(this::isLoggable) + .toList(); + } + fields.addAll(classFields); + + methods.addAll( + clazz.getEnclosedElements().stream() + .filter(e -> e instanceof ExecutableElement) + .map(e -> (ExecutableElement) e) + .filter(notSkipped) + .filter(optedIn) + .filter(e -> !e.getModifiers().contains(Modifier.STATIC)) + .filter(e -> e.getModifiers().contains(Modifier.PUBLIC)) + .filter(e -> e.getParameters().isEmpty()) + .filter(e -> e.getReceiverType() != null) + .filter(kIsBuiltInJavaMethod.negate()) + .filter(this::isLoggable) + .filter(e -> !isSimpleGetterMethodForLoggedField(e, classFields)) + .toList()); + + TypeElement superclass = + (TypeElement) m_processingEnv.getTypeUtils().asElement(clazz.getSuperclass()); + if (superclass != null) { + collectLoggables(superclass, fields, methods); + } + } + private boolean isLoggable(Element element) { return m_handlers.stream().anyMatch(h -> h.isLoggable(element)); } diff --git a/epilogue-processor/src/test/java/edu/wpi/first/epilogue/processor/AnnotationProcessorTest.java b/epilogue-processor/src/test/java/edu/wpi/first/epilogue/processor/AnnotationProcessorTest.java index 8f1d9f2b19..50795a45b0 100644 --- a/epilogue-processor/src/test/java/edu/wpi/first/epilogue/processor/AnnotationProcessorTest.java +++ b/epilogue-processor/src/test/java/edu/wpi/first/epilogue/processor/AnnotationProcessorTest.java @@ -42,8 +42,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", double.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -51,7 +64,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); + backend.log("x", ((double) $x.get(object))); } } } @@ -80,8 +93,23 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + private static final VarHandle $y; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", double.class); + $y = lookup.findVarHandle(Example.class, "y", int.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -89,8 +117,8 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); - backend.log("y", object.y); + backend.log("x", ((double) $x.get(object))); + backend.log("y", ((int) $y.get(object))); } } } @@ -182,8 +210,23 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + private static final VarHandle $y; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", double.class); + $y = lookup.findVarHandle(Example.class, "y", double.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -191,8 +234,8 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); - backend.log("y", object.y); + backend.log("x", ((double) $x.get(object))); + backend.log("y", ((double) $y.get(object))); } } } @@ -378,8 +421,25 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $low; + private static final VarHandle $medium; + private static final VarHandle $high; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $low = lookup.findVarHandle(Example.class, "low", double.class); + $medium = lookup.findVarHandle(Example.class, "medium", int.class); + $high = lookup.findVarHandle(Example.class, "high", long.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -387,13 +447,13 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("low", object.low); + backend.log("low", ((double) $low.get(object))); } if (Epilogue.shouldLog(Logged.Importance.INFO)) { - backend.log("medium", object.medium); + backend.log("medium", ((int) $medium.get(object))); } if (Epilogue.shouldLog(Logged.Importance.CRITICAL)) { - backend.log("high", object.high); + backend.log("high", ((long) $high.get(object))); } } } @@ -426,8 +486,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $enumValue; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $enumValue = lookup.findVarHandle(Example.class, "enumValue", edu.wpi.first.epilogue.Example.E.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -435,7 +508,145 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("enumValue", object.enumValue); + backend.log("enumValue", ((edu.wpi.first.epilogue.Example.E) $enumValue.get(object))); + } + } + } + """; + + assertLoggerGenerates(source, expectedGeneratedSource); + } + + @Test + void superclassStillOptIn() { + String source = + """ + package edu.wpi.first.epilogue; + + // nothing should be logged from BaseExample + class BaseExample { + public double x; + public double getValue() { return 2.0; } + } + + @Logged + class Example extends BaseExample { + double y; + } + """; + + String expectedGeneratedSource = + """ + package edu.wpi.first.epilogue; + + import edu.wpi.first.epilogue.Logged; + import edu.wpi.first.epilogue.Epilogue; + import edu.wpi.first.epilogue.logging.ClassSpecificLogger; + import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; + + public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $y; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $y = lookup.findVarHandle(Example.class, "y", double.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + + public ExampleLogger() { + super(Example.class); + } + + @Override + public void update(EpilogueBackend backend, Example object) { + if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { + backend.log("y", ((double) $y.get(object))); + } + } + } + """; + + assertLoggerGenerates(source, expectedGeneratedSource); + } + + @Test + void superclass() { + String source = + """ + package edu.wpi.first.epilogue; + + class Grandparent { + @Logged + public double a; + @Logged public double getB() { return 0; } + public double getC() { return 1; } // not annotated, not logged + } + + @Logged + class BaseExample extends Grandparent { + protected double d; + public double e; + private double f; + double g; + public double getValue() { return 2.0; } + private double getOtherValue() { return 3.0; } // private, not logged + } + + @Logged + class Example extends BaseExample { + double h; + } + """; + + String expectedGeneratedSource = + """ + package edu.wpi.first.epilogue; + + import edu.wpi.first.epilogue.Logged; + import edu.wpi.first.epilogue.Epilogue; + import edu.wpi.first.epilogue.logging.ClassSpecificLogger; + import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; + + public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $h; + private static final VarHandle $d; + private static final VarHandle $f; + private static final VarHandle $g; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $h = lookup.findVarHandle(Example.class, "h", double.class); + $d = lookup.findVarHandle(Example.class, "d", double.class); + $f = lookup.findVarHandle(Example.class, "f", double.class); + $g = lookup.findVarHandle(Example.class, "g", double.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + + public ExampleLogger() { + super(Example.class); + } + + @Override + public void update(EpilogueBackend backend, Example object) { + if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { + backend.log("h", ((double) $h.get(object))); + backend.log("d", ((double) $d.get(object))); + backend.log("e", object.e); + backend.log("f", ((double) $f.get(object))); + backend.log("g", ((double) $g.get(object))); + backend.log("a", object.a); + backend.log("getValue", object.getValue()); + backend.log("getB", object.getB()); } } } @@ -470,8 +681,23 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + private static final VarHandle $arr1; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", byte.class); + $arr1 = lookup.findVarHandle(Example.class, "arr1", byte[].class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -479,8 +705,8 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); - backend.log("arr1", object.arr1); + backend.log("x", ((byte) $x.get(object))); + backend.log("arr1", ((byte[]) $arr1.get(object))); backend.log("getX", object.getX()); backend.log("getArr1", object.getArr1()); } @@ -517,8 +743,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", char.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -526,7 +765,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); + backend.log("x", ((char) $x.get(object))); backend.log("getX", object.getX()); } } @@ -562,8 +801,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", short.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -571,7 +823,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); + backend.log("x", ((short) $x.get(object))); backend.log("getX", object.getX()); } } @@ -607,8 +859,23 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + private static final VarHandle $arr1; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", int.class); + $arr1 = lookup.findVarHandle(Example.class, "arr1", int[].class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -616,8 +883,8 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); - backend.log("arr1", object.arr1); + backend.log("x", ((int) $x.get(object))); + backend.log("arr1", ((int[]) $arr1.get(object))); backend.log("getX", object.getX()); backend.log("getArr1", object.getArr1()); } @@ -654,8 +921,23 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + private static final VarHandle $arr1; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", long.class); + $arr1 = lookup.findVarHandle(Example.class, "arr1", long[].class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -663,8 +945,8 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); - backend.log("arr1", object.arr1); + backend.log("x", ((long) $x.get(object))); + backend.log("arr1", ((long[]) $arr1.get(object))); backend.log("getX", object.getX()); backend.log("getArr1", object.getArr1()); } @@ -701,8 +983,23 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + private static final VarHandle $arr1; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", float.class); + $arr1 = lookup.findVarHandle(Example.class, "arr1", float[].class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -710,8 +1007,8 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); - backend.log("arr1", object.arr1); + backend.log("x", ((float) $x.get(object))); + backend.log("arr1", ((float[]) $arr1.get(object))); backend.log("getX", object.getX()); backend.log("getArr1", object.getArr1()); } @@ -751,8 +1048,23 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + private static final VarHandle $arr1; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", double.class); + $arr1 = lookup.findVarHandle(Example.class, "arr1", double[].class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -760,8 +1072,8 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); - backend.log("arr1", object.arr1); + backend.log("x", ((double) $x.get(object))); + backend.log("arr1", ((double[]) $arr1.get(object))); backend.log("getX", object.getX()); backend.log("getArr1", object.getArr1()); } @@ -800,8 +1112,23 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + private static final VarHandle $arr1; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", boolean.class); + $arr1 = lookup.findVarHandle(Example.class, "arr1", boolean[].class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -809,8 +1136,8 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); - backend.log("arr1", object.arr1); + backend.log("x", ((boolean) $x.get(object))); + backend.log("arr1", ((boolean[]) $arr1.get(object))); backend.log("getX", object.getX()); backend.log("getArr1", object.getArr1()); } @@ -850,8 +1177,25 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + private static final VarHandle $arr1; + private static final VarHandle $list; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", java.lang.String.class); + $arr1 = lookup.findVarHandle(Example.class, "arr1", java.lang.String[].class); + $list = lookup.findVarHandle(Example.class, "list", java.util.List.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -859,9 +1203,9 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); - backend.log("arr1", object.arr1); - backend.log("list", object.list); + backend.log("x", ((java.lang.String) $x.get(object))); + backend.log("arr1", ((java.lang.String[]) $arr1.get(object))); + backend.log("list", ((java.util.List) $list.get(object))); backend.log("getX", object.getX()); backend.log("getArr1", object.getArr1()); } @@ -909,8 +1253,25 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + private static final VarHandle $arr1; + private static final VarHandle $list; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", edu.wpi.first.epilogue.Example.Structable.class); + $arr1 = lookup.findVarHandle(Example.class, "arr1", edu.wpi.first.epilogue.Example.Structable[].class); + $list = lookup.findVarHandle(Example.class, "list", java.util.List.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -918,9 +1279,9 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x, edu.wpi.first.epilogue.Example.Structable.struct); - backend.log("arr1", object.arr1, edu.wpi.first.epilogue.Example.Structable.struct); - backend.log("list", object.list, edu.wpi.first.epilogue.Example.Structable.struct); + backend.log("x", ((edu.wpi.first.epilogue.Example.Structable) $x.get(object)), edu.wpi.first.epilogue.Example.Structable.struct); + backend.log("arr1", ((edu.wpi.first.epilogue.Example.Structable[]) $arr1.get(object)), edu.wpi.first.epilogue.Example.Structable.struct); + backend.log("list", ((java.util.List) $list.get(object)), edu.wpi.first.epilogue.Example.Structable.struct); backend.log("getX", object.getX(), edu.wpi.first.epilogue.Example.Structable.struct); backend.log("getArr1", object.getArr1(), edu.wpi.first.epilogue.Example.Structable.struct); } @@ -960,8 +1321,27 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $list; + private static final VarHandle $set; + private static final VarHandle $queue; + private static final VarHandle $stack; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $list = lookup.findVarHandle(Example.class, "list", java.util.List.class); + $set = lookup.findVarHandle(Example.class, "set", java.util.Set.class); + $queue = lookup.findVarHandle(Example.class, "queue", java.util.Queue.class); + $stack = lookup.findVarHandle(Example.class, "stack", java.util.Stack.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -969,10 +1349,10 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("list", object.list); - backend.log("set", object.set); - backend.log("queue", object.queue); - backend.log("stack", object.stack); + backend.log("list", ((java.util.List) $list.get(object))); + backend.log("set", ((java.util.Set) $set.get(object))); + backend.log("queue", ((java.util.Queue) $queue.get(object))); + backend.log("stack", ((java.util.Stack) $stack.get(object))); } } } @@ -1141,8 +1521,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $value; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $value = lookup.findVarHandle(Example.class, "value", java.lang.String.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -1150,7 +1543,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("value", object.value); + backend.log("value", ((java.lang.String) $value.get(object))); backend.log("upcast", object.upcast()); } } @@ -1193,8 +1586,23 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $child; + private static final VarHandle $io; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $child = lookup.findVarHandle(Example.class, "child", edu.wpi.first.epilogue.Child.class); + $io = lookup.findVarHandle(Example.class, "io", edu.wpi.first.epilogue.IO.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -1202,8 +1610,8 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - Epilogue.childLogger.tryUpdate(backend.getNested("child"), object.child, Epilogue.getConfig().errorHandler); - Epilogue.ioLogger.tryUpdate(backend.getNested("io"), object.io, Epilogue.getConfig().errorHandler); + Epilogue.childLogger.tryUpdate(backend.getNested("child"), ((edu.wpi.first.epilogue.Child) $child.get(object)), Epilogue.getConfig().errorHandler); + Epilogue.ioLogger.tryUpdate(backend.getNested("io"), ((edu.wpi.first.epilogue.IO) $io.get(object)), Epilogue.getConfig().errorHandler); } } } @@ -1280,8 +1688,27 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $asInterface; + private static final VarHandle $firstImpl; + private static final VarHandle $secondImpl; + private static final VarHandle $complex; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $asInterface = lookup.findVarHandle(Example.class, "asInterface", edu.wpi.first.epilogue.IFace.class); + $firstImpl = lookup.findVarHandle(Example.class, "firstImpl", edu.wpi.first.epilogue.Impl1.class); + $secondImpl = lookup.findVarHandle(Example.class, "secondImpl", edu.wpi.first.epilogue.Impl2.class); + $complex = lookup.findVarHandle(Example.class, "complex", edu.wpi.first.epilogue.I.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -1289,7 +1716,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - var $$asInterface = object.asInterface; + var $$asInterface = ((edu.wpi.first.epilogue.IFace) $asInterface.get(object)); if ($$asInterface instanceof edu.wpi.first.epilogue.Impl1 edu_wpi_first_epilogue_Impl1) { Epilogue.impl1Logger.tryUpdate(backend.getNested("asInterface"), edu_wpi_first_epilogue_Impl1, Epilogue.getConfig().errorHandler); } else if ($$asInterface instanceof edu.wpi.first.epilogue.Impl2 edu_wpi_first_epilogue_Impl2) { @@ -1298,9 +1725,9 @@ class AnnotationProcessorTest { // Base type edu.wpi.first.epilogue.IFace Epilogue.iFaceLogger.tryUpdate(backend.getNested("asInterface"), $$asInterface, Epilogue.getConfig().errorHandler); }; - Epilogue.impl1Logger.tryUpdate(backend.getNested("firstImpl"), object.firstImpl, Epilogue.getConfig().errorHandler); - Epilogue.impl2Logger.tryUpdate(backend.getNested("secondImpl"), object.secondImpl, Epilogue.getConfig().errorHandler); - var $$complex = object.complex; + Epilogue.impl1Logger.tryUpdate(backend.getNested("firstImpl"), ((edu.wpi.first.epilogue.Impl1) $firstImpl.get(object)), Epilogue.getConfig().errorHandler); + Epilogue.impl2Logger.tryUpdate(backend.getNested("secondImpl"), ((edu.wpi.first.epilogue.Impl2) $secondImpl.get(object)), Epilogue.getConfig().errorHandler); + var $$complex = ((edu.wpi.first.epilogue.I) $complex.get(object)); if ($$complex instanceof edu.wpi.first.epilogue.ConcreteLogged edu_wpi_first_epilogue_ConcreteLogged) { Epilogue.concreteLoggedLogger.tryUpdate(backend.getNested("complex"), edu_wpi_first_epilogue_ConcreteLogged, Epilogue.getConfig().errorHandler); } else if ($$complex instanceof edu.wpi.first.epilogue.I4 edu_wpi_first_epilogue_I4) { @@ -1343,8 +1770,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class Outer$ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Outer.Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Outer.Example.class, "x", double.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public Outer$ExampleLogger() { super(Outer.Example.class); } @@ -1352,7 +1792,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Outer.Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); + backend.log("x", ((double) $x.get(object))); } } } @@ -1389,8 +1829,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class A$B$C$D$ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + + static { + try { + var lookup = MethodHandles.privateLookupIn(A.B.C.D.Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(A.B.C.D.Example.class, "x", double.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public A$B$C$D$ExampleLogger() { super(A.B.C.D.Example.class); } @@ -1398,7 +1851,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, A.B.C.D.Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); + backend.log("x", ((double) $x.get(object))); } } } @@ -1429,8 +1882,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class CustomExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Outer.Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Outer.Example.class, "x", double.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public CustomExampleLogger() { super(Outer.Example.class); } @@ -1438,7 +1904,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Outer.Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); + backend.log("x", ((double) $x.get(object))); } } } @@ -1482,8 +1948,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $theField; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $theField = lookup.findVarHandle(Example.class, "theField", edu.wpi.first.epilogue.I.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -1491,7 +1970,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - var $$theField = object.theField; + var $$theField = ((edu.wpi.first.epilogue.I) $theField.get(object)); if ($$theField instanceof edu.wpi.first.epilogue.Base edu_wpi_first_epilogue_Base) { Epilogue.baseLogger.tryUpdate(backend.getNested("theField"), edu_wpi_first_epilogue_Base, Epilogue.getConfig().errorHandler); } else if ($$theField instanceof edu.wpi.first.epilogue.ExtendingInterface edu_wpi_first_epilogue_ExtendingInterface) { @@ -1594,8 +2073,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $i; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $i = lookup.findVarHandle(Example.class, "i", edu.wpi.first.epilogue.Implicit.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -1603,7 +2095,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - Epilogue.implicitLogger.tryUpdate(backend.getNested("i"), object.i, Epilogue.getConfig().errorHandler); + Epilogue.implicitLogger.tryUpdate(backend.getNested("i"), ((edu.wpi.first.epilogue.Implicit) $i.get(object)), Epilogue.getConfig().errorHandler); } } } @@ -1648,8 +2140,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $point; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $point = lookup.findVarHandle(Example.class, "point", edu.wpi.first.epilogue.Point.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -1657,7 +2162,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - Epilogue.customPointLogger.tryUpdate(backend.getNested("point"), object.point, Epilogue.getConfig().errorHandler); + Epilogue.customPointLogger.tryUpdate(backend.getNested("point"), ((edu.wpi.first.epilogue.Point) $point.get(object)), Epilogue.getConfig().errorHandler); } } } @@ -1703,8 +2208,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $vec; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $vec = lookup.findVarHandle(Example.class, "vec", edu.wpi.first.math.Vector.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -1712,7 +2230,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - Epilogue.vectorLogger.tryUpdate(backend.getNested("vec"), object.vec, Epilogue.getConfig().errorHandler); + Epilogue.vectorLogger.tryUpdate(backend.getNested("vec"), ((edu.wpi.first.math.Vector) $vec.get(object)), Epilogue.getConfig().errorHandler); } } } @@ -1899,8 +2417,21 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $x; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $x = lookup.findVarHandle(Example.class, "x", double.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -1908,7 +2439,7 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("x", object.x); + backend.log("x", ((double) $x.get(object))); backend.log("withANoOpTransform", object.withANoOpTransform()); backend.log("withTemp", object.withTemp()); } @@ -1951,8 +2482,27 @@ class AnnotationProcessorTest { import edu.wpi.first.epilogue.Epilogue; import edu.wpi.first.epilogue.logging.ClassSpecificLogger; import edu.wpi.first.epilogue.logging.EpilogueBackend; + import java.lang.invoke.MethodHandles; + import java.lang.invoke.VarHandle; public class ExampleLogger extends ClassSpecificLogger { + private static final VarHandle $m_memberPrefix; + private static final VarHandle $kConstantPrefix; + private static final VarHandle $k_otherConstantPrefix; + private static final VarHandle $s_otherPrefix; + + static { + try { + var lookup = MethodHandles.privateLookupIn(Example.class, MethodHandles.lookup()); + $m_memberPrefix = lookup.findVarHandle(Example.class, "m_memberPrefix", double.class); + $kConstantPrefix = lookup.findVarHandle(Example.class, "kConstantPrefix", double.class); + $k_otherConstantPrefix = lookup.findVarHandle(Example.class, "k_otherConstantPrefix", double.class); + $s_otherPrefix = lookup.findVarHandle(Example.class, "s_otherPrefix", double.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("[EPILOGUE] Could not load private fields for logging!", e); + } + } + public ExampleLogger() { super(Example.class); } @@ -1960,10 +2510,10 @@ class AnnotationProcessorTest { @Override public void update(EpilogueBackend backend, Example object) { if (Epilogue.shouldLog(Logged.Importance.DEBUG)) { - backend.log("Member Prefix", object.m_memberPrefix); - backend.log("Constant Prefix", object.kConstantPrefix); - backend.log("Other Constant Prefix", object.k_otherConstantPrefix); - backend.log("Other Prefix", object.s_otherPrefix); + backend.log("Member Prefix", ((double) $m_memberPrefix.get(object))); + backend.log("Constant Prefix", ((double) $kConstantPrefix.get(object))); + backend.log("Other Constant Prefix", ((double) $k_otherConstantPrefix.get(object))); + backend.log("Other Prefix", ((double) $s_otherPrefix.get(object))); backend.log("The Getter Method", object.getTheGetterMethod()); backend.log("optedOut", object.optedOut()); }