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,25 @@ 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 , optResult , mutableAst , node .expr ());
309314 }
310315
311- CelMutableExpr adaptedResult = maybeAdaptEvaluatedResult (result ).orElse (null );
316+ CelMutableExpr adaptedResult = maybeAdaptEvaluatedResult (cel . getTypeProvider (), result ).orElse (null );
312317 if (adaptedResult == null ) {
313318 return Optional .empty ();
314319 }
315320
316321 return Optional .of (astMutator .replaceSubtree (mutableAst , adaptedResult , node .id ()));
317322 }
318323
319- private Optional <CelMutableExpr > maybeAdaptEvaluatedResult (Object result ) {
324+ private Optional <CelMutableExpr > maybeAdaptEvaluatedResult (CelTypeProvider typeProvider , Object result ) {
320325 if (CelConstant .isConstantValue (result )) {
321326 return Optional .of (CelMutableExpr .ofConstant (CelConstant .ofObjectValue (result )));
322327 } else if (result instanceof Collection <?>) {
323328 Collection <?> collection = (Collection <?>) result ;
324329 List <CelMutableExpr > listElements = new ArrayList <>();
325330 for (Object evaluatedElement : collection ) {
326- CelMutableExpr adaptedExpr = maybeAdaptEvaluatedResult (evaluatedElement ).orElse (null );
331+ CelMutableExpr adaptedExpr = maybeAdaptEvaluatedResult (typeProvider , evaluatedElement ).orElse (null );
327332 if (adaptedExpr == null ) {
328333 return Optional .empty ();
329334 }
@@ -335,11 +340,11 @@ private Optional<CelMutableExpr> maybeAdaptEvaluatedResult(Object result) {
335340 Map <?, ?> map = (Map <?, ?>) result ;
336341 List <CelMutableMap .Entry > mapEntries = new ArrayList <>();
337342 for (Map .Entry <?, ?> entry : map .entrySet ()) {
338- CelMutableExpr adaptedKey = maybeAdaptEvaluatedResult (entry .getKey ()).orElse (null );
343+ CelMutableExpr adaptedKey = maybeAdaptEvaluatedResult (typeProvider , entry .getKey ()).orElse (null );
339344 if (adaptedKey == null ) {
340345 return Optional .empty ();
341346 }
342- CelMutableExpr adaptedValue = maybeAdaptEvaluatedResult (entry .getValue ()).orElse (null );
347+ CelMutableExpr adaptedValue = maybeAdaptEvaluatedResult (typeProvider , entry .getValue ()).orElse (null );
343348 if (adaptedValue == null ) {
344349 return Optional .empty ();
345350 }
@@ -364,14 +369,39 @@ private Optional<CelMutableExpr> maybeAdaptEvaluatedResult(Object result) {
364369 CelMutableExpr .ofConstant (CelConstant .ofValue (timestampStrArg )));
365370
366371 return Optional .of (CelMutableExpr .ofCall (timestampCall ));
372+ } else if (result instanceof Message ) {
373+ Message message = (Message ) result ;
374+ Optional <CelType > typeOpt = typeProvider .findType (message .getDescriptorForType ().getFullName ());
375+ if (!typeOpt .isPresent () || !(typeOpt .get () instanceof StructType )) {
376+ return Optional .empty ();
377+ }
378+ StructType structType = (StructType ) typeOpt .get ();
379+ List <CelMutableStruct .Entry > structEntries = new ArrayList <>();
380+ for (String fieldName : structType .fieldNames ()) {
381+ FieldDescriptor fieldDescriptor = message .getDescriptorForType ().findFieldByName (fieldName );
382+ if (fieldDescriptor == null ) {
383+ continue ;
384+ }
385+ if (!message .getAllFields ().containsKey (fieldDescriptor )) {
386+ continue ;
387+ }
388+ CelMutableExpr adaptedFieldExpr =
389+ maybeAdaptEvaluatedResult (typeProvider , message .getField (fieldDescriptor )).orElse (null );
390+ if (adaptedFieldExpr == null ) {
391+ return Optional .empty ();
392+ }
393+ structEntries .add (CelMutableStruct .Entry .create (0 , fieldName , adaptedFieldExpr ));
394+ }
395+ return Optional .of (
396+ CelMutableExpr .ofStruct (CelMutableStruct .create (structType .name (), structEntries )));
367397 }
368398
369399 // Evaluated result cannot be folded (e.g: unknowns)
370400 return Optional .empty ();
371401 }
372402
373403 private Optional <CelMutableAst > maybeRewriteOptional (
374- Optional <?> optResult , CelMutableAst mutableAst , CelMutableExpr expr ) {
404+ Cel cel , Optional <?> optResult , CelMutableAst mutableAst , CelMutableExpr expr ) {
375405 Object unwrappedResult = optResult .orElse (null );
376406 if (unwrappedResult == null ) {
377407 if (isCallToFunction (expr , Function .OPTIONAL_NONE .getFunction ())) {
@@ -387,7 +417,7 @@ private Optional<CelMutableAst> maybeRewriteOptional(
387417 return Optional .empty ();
388418 }
389419
390- CelMutableExpr adaptedResult = maybeAdaptEvaluatedResult (unwrappedResult ).orElse (null );
420+ CelMutableExpr adaptedResult = maybeAdaptEvaluatedResult (cel . getTypeProvider (), unwrappedResult ).orElse (null );
391421 if (adaptedResult == null ) {
392422 // Evaluated result is not an adaptable constant. Leave the optional as is.
393423 return Optional .empty ();
0 commit comments