2323import com .google .common .collect .ImmutableList ;
2424import com .google .common .collect .ImmutableSet ;
2525import com .google .errorprone .annotations .CanIgnoreReturnValue ;
26+ import com .google .protobuf .Descriptors .FieldDescriptor ;
27+ import com .google .protobuf .Message ;
2628import dev .cel .bundle .Cel ;
2729import dev .cel .common .CelAbstractSyntaxTree ;
2830import dev .cel .common .CelMutableAst ;
4244import dev .cel .common .navigation .CelNavigableMutableAst ;
4345import dev .cel .common .navigation .CelNavigableMutableExpr ;
4446import dev .cel .common .navigation .TraversalOrder ;
47+ import dev .cel .common .types .CelType ;
48+ import dev .cel .common .types .CelTypeProvider ;
4549import dev .cel .common .types .SimpleType ;
50+ import dev .cel .common .types .StructType ;
4651import dev .cel .extensions .CelOptionalLibrary .Function ;
4752import dev .cel .optimizer .AstMutator ;
4853import dev .cel .optimizer .CelAstOptimizer ;
@@ -305,25 +310,28 @@ private Optional<CelMutableAst> maybeFold(
305310 // ex2: optional.ofNonZeroValue(5) -> optional.of(5)
306311 if (result instanceof Optional <?>) {
307312 Optional <?> optResult = ((Optional <?>) result );
308- return maybeRewriteOptional (optResult , mutableAst , node .expr ());
313+ return maybeRewriteOptional (cel . getTypeProvider (), optResult , mutableAst , node .expr ());
309314 }
310315
311- CelMutableExpr adaptedResult = maybeAdaptEvaluatedResult (result ).orElse (null );
316+ CelMutableExpr adaptedResult =
317+ maybeAdaptEvaluatedResult (cel .getTypeProvider (), result ).orElse (null );
312318 if (adaptedResult == null ) {
313319 return Optional .empty ();
314320 }
315321
316322 return Optional .of (astMutator .replaceSubtree (mutableAst , adaptedResult , node .id ()));
317323 }
318324
319- private Optional <CelMutableExpr > maybeAdaptEvaluatedResult (Object result ) {
325+ private Optional <CelMutableExpr > maybeAdaptEvaluatedResult (
326+ CelTypeProvider typeProvider , Object result ) {
320327 if (CelConstant .isConstantValue (result )) {
321328 return Optional .of (CelMutableExpr .ofConstant (CelConstant .ofObjectValue (result )));
322329 } else if (result instanceof Collection <?>) {
323330 Collection <?> collection = (Collection <?>) result ;
324331 List <CelMutableExpr > listElements = new ArrayList <>();
325332 for (Object evaluatedElement : collection ) {
326- CelMutableExpr adaptedExpr = maybeAdaptEvaluatedResult (evaluatedElement ).orElse (null );
333+ CelMutableExpr adaptedExpr =
334+ maybeAdaptEvaluatedResult (typeProvider , evaluatedElement ).orElse (null );
327335 if (adaptedExpr == null ) {
328336 return Optional .empty ();
329337 }
@@ -335,11 +343,13 @@ private Optional<CelMutableExpr> maybeAdaptEvaluatedResult(Object result) {
335343 Map <?, ?> map = (Map <?, ?>) result ;
336344 List <CelMutableMap .Entry > mapEntries = new ArrayList <>();
337345 for (Map .Entry <?, ?> entry : map .entrySet ()) {
338- CelMutableExpr adaptedKey = maybeAdaptEvaluatedResult (entry .getKey ()).orElse (null );
346+ CelMutableExpr adaptedKey =
347+ maybeAdaptEvaluatedResult (typeProvider , entry .getKey ()).orElse (null );
339348 if (adaptedKey == null ) {
340349 return Optional .empty ();
341350 }
342- CelMutableExpr adaptedValue = maybeAdaptEvaluatedResult (entry .getValue ()).orElse (null );
351+ CelMutableExpr adaptedValue =
352+ maybeAdaptEvaluatedResult (typeProvider , entry .getValue ()).orElse (null );
343353 if (adaptedValue == null ) {
344354 return Optional .empty ();
345355 }
@@ -364,14 +374,40 @@ private Optional<CelMutableExpr> maybeAdaptEvaluatedResult(Object result) {
364374 CelMutableExpr .ofConstant (CelConstant .ofValue (timestampStrArg )));
365375
366376 return Optional .of (CelMutableExpr .ofCall (timestampCall ));
377+ } else if (result instanceof Message ) {
378+ Message message = (Message ) result ;
379+ Optional <CelType > typeOpt =
380+ typeProvider .findType (message .getDescriptorForType ().getFullName ());
381+ if (!typeOpt .isPresent () || !(typeOpt .get () instanceof StructType )) {
382+ return Optional .empty ();
383+ }
384+ StructType structType = (StructType ) typeOpt .get ();
385+ List <CelMutableStruct .Entry > structEntries = new ArrayList <>();
386+ for (String fieldName : structType .fieldNames ()) {
387+ FieldDescriptor fieldDescriptor = message .getDescriptorForType ().findFieldByName (fieldName );
388+ if (fieldDescriptor == null ) {
389+ continue ;
390+ }
391+ if (!message .getAllFields ().containsKey (fieldDescriptor )) {
392+ continue ;
393+ }
394+ CelMutableExpr adaptedFieldExpr =
395+ maybeAdaptEvaluatedResult (typeProvider , message .getField (fieldDescriptor )).orElse (null );
396+ if (adaptedFieldExpr == null ) {
397+ return Optional .empty ();
398+ }
399+ structEntries .add (CelMutableStruct .Entry .create (0 , fieldName , adaptedFieldExpr ));
400+ }
401+ return Optional .of (
402+ CelMutableExpr .ofStruct (CelMutableStruct .create (structType .name (), structEntries )));
367403 }
368404
369405 // Evaluated result cannot be folded (e.g: unknowns)
370406 return Optional .empty ();
371407 }
372408
373409 private Optional <CelMutableAst > maybeRewriteOptional (
374- Optional <?> optResult , CelMutableAst mutableAst , CelMutableExpr expr ) {
410+ CelTypeProvider typeProvider , Optional <?> optResult , CelMutableAst mutableAst , CelMutableExpr expr ) {
375411 Object unwrappedResult = optResult .orElse (null );
376412 if (unwrappedResult == null ) {
377413 if (isCallToFunction (expr , Function .OPTIONAL_NONE .getFunction ())) {
@@ -387,7 +423,8 @@ private Optional<CelMutableAst> maybeRewriteOptional(
387423 return Optional .empty ();
388424 }
389425
390- CelMutableExpr adaptedResult = maybeAdaptEvaluatedResult (unwrappedResult ).orElse (null );
426+ CelMutableExpr adaptedResult =
427+ maybeAdaptEvaluatedResult (typeProvider , unwrappedResult ).orElse (null );
391428 if (adaptedResult == null ) {
392429 // Evaluated result is not an adaptable constant. Leave the optional as is.
393430 return Optional .empty ();
0 commit comments