| 899 | } |
| 900 | |
| 901 | void PreVisitSelect(const cel::Expr& expr, |
| 902 | const cel::SelectExpr& select_expr) override { |
| 903 | if (!progress_status_.ok()) { |
| 904 | return; |
| 905 | } |
| 906 | if (!ValidateOrError( |
| 907 | !select_expr.field().empty(), |
| 908 | "invalid expression: select 'field' must not be empty")) { |
| 909 | return; |
| 910 | } |
| 911 | if (!ValidateOrError( |
| 912 | select_expr.has_operand() && |
| 913 | select_expr.operand().kind_case() != |
| 914 | cel::ExprKindCase::kUnspecifiedExpr, |
| 915 | "invalid expression: select must specify an operand")) { |
| 916 | return; |
| 917 | } |
| 918 | |
| 919 | // Not exactly the cleanest solution - we peek into child of |
| 920 | // select_expr. |
| 921 | // Chain of multiple SELECT ending with IDENT can represent namespaced |
| 922 | // entity. |
| 923 | if (!select_expr.test_only() && (select_expr.operand().has_ident_expr() || |
| 924 | select_expr.operand().has_select_expr())) { |
| 925 | // select expressions are pushed in reverse order: |
| 926 | // google.type.Expr is pushed as: |
| 927 | // - field: 'Expr' |
| 928 | // - field: 'type' |
| 929 | // - id: 'google' |
| 930 | // |
| 931 | // The search order though is as follows: |
| 932 | // - id: 'google.type.Expr' |
| 933 | // - id: 'google.type', field: 'Expr' |
| 934 | // - id: 'google', field: 'type', field: 'Expr' |
| 935 | for (size_t i = 0; i < namespace_stack_.size(); i++) { |
| 936 | auto ns = namespace_stack_[i]; |
| 937 | namespace_stack_[i] = { |
| 938 | ns.first, absl::StrCat(select_expr.field(), ".", ns.second)}; |
| 939 | } |
| 940 | namespace_stack_.push_back({&expr, select_expr.field()}); |
| 941 | } else { |
| 942 | namespace_stack_.clear(); |
| 943 | } |
| 944 | } |
| 945 | |
| 946 | // Select node handler. |
| 947 | // Invoked after child nodes are processed. |
nothing calls this directly
no test coverage detected