diff --git a/core/src/main/java/org/projectnessie/cel/checker/Checker.java b/core/src/main/java/org/projectnessie/cel/checker/Checker.java index 56bed6f8..a823e005 100644 --- a/core/src/main/java/org/projectnessie/cel/checker/Checker.java +++ b/core/src/main/java/org/projectnessie/cel/checker/Checker.java @@ -69,6 +69,7 @@ public final class Checker { private final SourceInfo sourceInfo; private final Map types = new HashMap<>(); private final Map references = new HashMap<>(); + private final Map fieldTypes = new HashMap<>(); private Checker( CheckerEnv env, @@ -643,7 +644,7 @@ FieldType lookupFieldType(Location l, String messageType, String fieldName) { return null; } - FieldType ft = env.provider.findFieldType(messageType, fieldName); + FieldType ft = findFieldType(messageType, fieldName); if (ft != null) { return ft; } @@ -652,6 +653,19 @@ FieldType lookupFieldType(Location l, String messageType, String fieldName) { return null; } + private FieldType findFieldType(String messageType, String fieldName) { + String key = messageType + '\n' + fieldName; + FieldType ft = fieldTypes.get(key); + if (ft != null) { + return ft; + } + ft = env.provider.findFieldType(messageType, fieldName); + if (ft != null) { + fieldTypes.put(key, ft); + } + return ft; + } + void setType(Expr.Builder e, Type t) { Type old = types.get(e.getId()); if (old != null && !old.equals(t)) { diff --git a/core/src/main/java/org/projectnessie/cel/interpreter/InterpretablePlanner.java b/core/src/main/java/org/projectnessie/cel/interpreter/InterpretablePlanner.java index e247005b..cce8a3e8 100644 --- a/core/src/main/java/org/projectnessie/cel/interpreter/InterpretablePlanner.java +++ b/core/src/main/java/org/projectnessie/cel/interpreter/InterpretablePlanner.java @@ -126,6 +126,7 @@ final class Planner implements InterpretablePlanner { private final Container container; private final Map refMap; private final Map typeMap; + private final Map fieldTypes = new HashMap<>(); private final InterpretableDecorator[] decorators; Planner( @@ -249,7 +250,7 @@ Interpretable planSelect(Expr expr) { FieldType fieldType = null; Type opType = typeMap.get(sel.getOperand().getId()); if (opType != null && !opType.getMessageType().isEmpty()) { - FieldType ft = provider.findFieldType(opType.getMessageType(), sel.getField()); + FieldType ft = findFieldType(opType.getMessageType(), sel.getField()); if (ft != null && ft.isSet != null && ft.getFrom != null) { fieldType = ft; } @@ -273,7 +274,11 @@ Interpretable planSelect(Expr expr) { return new EvalTestOnly(expr.getId(), op, stringOf(sel.getField()), fieldType); } // Build a qualifier. - Qualifier qual = attrFactory.newQualifier(opType, expr.getId(), sel.getField()); + Qualifier qual = + fieldType != null + ? new AttributeFactory.FieldQualifier( + expr.getId(), sel.getField(), fieldType, adapter) + : attrFactory.newQualifier(opType, expr.getId(), sel.getField()); if (qual == null) { return null; } @@ -292,6 +297,19 @@ Interpretable planSelect(Expr expr) { return relAttr; } + private FieldType findFieldType(String messageType, String fieldName) { + String key = messageType + '\n' + fieldName; + FieldType ft = fieldTypes.get(key); + if (ft != null) { + return ft; + } + ft = provider.findFieldType(messageType, fieldName); + if (ft != null) { + fieldTypes.put(key, ft); + } + return ft; + } + /** * planCall creates a callable Interpretable while specializing for common functions and * invocation patterns. Specifically, conditional operators &&, ||, ?:, and (in)equality