Coverage Report

Created: 2026-07-16 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/eval/eval/attribute_utility.cc
Line
Count
Source
1
#include "eval/eval/attribute_utility.h"
2
3
#include <cstdint>
4
#include <string>
5
#include <utility>
6
7
#include "absl/status/statusor.h"
8
#include "absl/types/optional.h"
9
#include "absl/types/span.h"
10
#include "base/attribute.h"
11
#include "base/attribute_set.h"
12
#include "base/function_result.h"
13
#include "base/function_result_set.h"
14
#include "base/internal/unknown_set.h"
15
#include "common/casting.h"
16
#include "common/function_descriptor.h"
17
#include "common/unknown.h"
18
#include "common/value.h"
19
#include "eval/eval/attribute_trail.h"
20
#include "eval/internal/errors.h"
21
#include "internal/status_macros.h"
22
#include "runtime/internal/attribute_matcher.h"
23
24
namespace google::api::expr::runtime {
25
26
using ::cel::Attribute;
27
using ::cel::AttributePattern;
28
using ::cel::AttributeSet;
29
using ::cel::Cast;
30
using ::cel::ErrorValue;
31
using ::cel::FunctionResult;
32
using ::cel::FunctionResultSet;
33
using ::cel::InstanceOf;
34
using ::cel::UnknownValue;
35
using ::cel::Value;
36
using ::cel::base_internal::UnknownSet;
37
using ::cel::runtime_internal::AttributeMatcher;
38
39
using Accumulator = AttributeUtility::Accumulator;
40
using MatchResult = AttributeMatcher::MatchResult;
41
42
DefaultAttributeMatcher::DefaultAttributeMatcher(
43
    absl::Span<const AttributePattern> unknown_patterns,
44
    absl::Span<const AttributePattern> missing_patterns)
45
15.8k
    : unknown_patterns_(unknown_patterns),
46
15.8k
      missing_patterns_(missing_patterns) {}
47
48
0
DefaultAttributeMatcher::DefaultAttributeMatcher() = default;
49
50
AttributeMatcher::MatchResult MatchAgainstPatterns(
51
0
    absl::Span<const AttributePattern> patterns, const Attribute& attr) {
52
0
  MatchResult result = MatchResult::NONE;
53
0
  for (const auto& pattern : patterns) {
54
0
    auto current_match = pattern.IsMatch(attr);
55
0
    if (current_match == cel::AttributePattern::MatchType::FULL) {
56
0
      return MatchResult::FULL;
57
0
    }
58
0
    if (current_match == cel::AttributePattern::MatchType::PARTIAL) {
59
0
      result = MatchResult::PARTIAL;
60
0
    }
61
0
  }
62
0
  return result;
63
0
}
64
65
DefaultAttributeMatcher::MatchResult DefaultAttributeMatcher::CheckForUnknown(
66
0
    const Attribute& attr) const {
67
0
  return MatchAgainstPatterns(unknown_patterns_, attr);
68
0
}
69
70
DefaultAttributeMatcher::MatchResult DefaultAttributeMatcher::CheckForMissing(
71
0
    const Attribute& attr) const {
72
0
  return MatchAgainstPatterns(missing_patterns_, attr);
73
0
}
74
75
bool AttributeUtility::CheckForMissingAttribute(
76
0
    const AttributeTrail& trail) const {
77
0
  if (trail.empty()) {
78
0
    return false;
79
0
  }
80
  // Missing attributes are only treated as errors if the attribute exactly
81
  // matches (so no guard against passing partial state to a function as with
82
  // unknowns). This was initially a design oversight, but is difficult to
83
  // change now.
84
0
  return matcher_->CheckForMissing(trail.attribute()) ==
85
0
         AttributeMatcher::MatchResult::FULL;
86
0
}
87
88
// Checks whether particular corresponds to any patterns that define unknowns.
89
bool AttributeUtility::CheckForUnknown(const AttributeTrail& trail,
90
0
                                       bool use_partial) const {
91
0
  if (trail.empty()) {
92
0
    return false;
93
0
  }
94
0
  MatchResult result = matcher_->CheckForUnknown(trail.attribute());
95
96
0
  if (result == MatchResult::FULL ||
97
0
      (use_partial && result == MatchResult::PARTIAL)) {
98
0
    return true;
99
0
  }
100
0
  return false;
101
0
}
102
103
// Creates merged UnknownAttributeSet.
104
// Scans over the args collection, merges any UnknownSets found in
105
// it together with initial_set (if initial_set is not null).
106
// Returns pointer to merged set or nullptr, if there were no sets to merge.
107
absl::optional<UnknownValue> AttributeUtility::MergeUnknowns(
108
0
    absl::Span<const cel::Value> args) const {
109
  // Empty unknown value may be used as a sentinel in some tests so need to
110
  // distinguish unset (nullopt) and empty(engaged empty value).
111
0
  absl::optional<UnknownSet> result_set;
112
113
0
  for (const auto& value : args) {
114
0
    if (!value->Is<cel::UnknownValue>()) continue;
115
0
    if (!result_set.has_value()) {
116
0
      result_set.emplace();
117
0
    }
118
0
    const auto& current_set = value.GetUnknown();
119
120
0
    cel::base_internal::UnknownSetAccess::Add(
121
0
        *result_set, UnknownSet(current_set.attribute_set(),
122
0
                                current_set.function_result_set()));
123
0
  }
124
125
0
  if (!result_set.has_value()) {
126
0
    return std::nullopt;
127
0
  }
128
129
0
  return UnknownValue(cel::Unknown(result_set->unknown_attributes(),
130
0
                                   result_set->unknown_function_results()));
131
0
}
132
133
UnknownValue AttributeUtility::MergeUnknownValues(
134
0
    const UnknownValue& left, const UnknownValue& right) const {
135
  // Empty unknown value may be used as a sentinel in some tests so need to
136
  // distinguish unset (nullopt) and empty(engaged empty value).
137
0
  AttributeSet attributes;
138
0
  FunctionResultSet function_results;
139
0
  attributes.Add(left.attribute_set());
140
0
  function_results.Add(left.function_result_set());
141
0
  attributes.Add(right.attribute_set());
142
0
  function_results.Add(right.function_result_set());
143
144
0
  return UnknownValue(
145
0
      cel::Unknown(std::move(attributes), std::move(function_results)));
146
0
}
147
148
// Creates merged UnknownAttributeSet.
149
// Scans over the args collection, determines if there matches to unknown
150
// patterns, merges attributes together with those from initial_set
151
// (if initial_set is not null).
152
// Returns pointer to merged set or nullptr, if there were no sets to merge.
153
AttributeSet AttributeUtility::CheckForUnknowns(
154
0
    absl::Span<const AttributeTrail> args, bool use_partial) const {
155
0
  AttributeSet attribute_set;
156
157
0
  for (const auto& trail : args) {
158
0
    if (CheckForUnknown(trail, use_partial)) {
159
0
      attribute_set.Add(trail.attribute());
160
0
    }
161
0
  }
162
163
0
  return attribute_set;
164
0
}
165
166
// Creates merged UnknownAttributeSet.
167
// Merges together attributes from UnknownAttributeSets found in the args
168
// collection, attributes from attr that match unknown pattern
169
// patterns, and attributes from initial_set
170
// (if initial_set is not null).
171
// Returns pointer to merged set or nullptr, if there were no sets to merge.
172
absl::optional<UnknownValue> AttributeUtility::IdentifyAndMergeUnknowns(
173
    absl::Span<const cel::Value> args, absl::Span<const AttributeTrail> attrs,
174
0
    bool use_partial) const {
175
0
  absl::optional<UnknownSet> result_set;
176
177
  // Identify new unknowns by attribute patterns.
178
0
  cel::AttributeSet attr_set = CheckForUnknowns(attrs, use_partial);
179
0
  if (!attr_set.empty()) {
180
0
    result_set.emplace(std::move(attr_set));
181
0
  }
182
183
  // merge down existing unknown sets
184
0
  absl::optional<UnknownValue> arg_unknowns = MergeUnknowns(args);
185
186
0
  if (!result_set.has_value()) {
187
    // No new unknowns so no need to check for presence of existing unknowns --
188
    // just forward.
189
0
    return arg_unknowns;
190
0
  }
191
192
0
  if (arg_unknowns.has_value()) {
193
0
    cel::base_internal::UnknownSetAccess::Add(
194
0
        *result_set, UnknownSet((*arg_unknowns).attribute_set(),
195
0
                                (*arg_unknowns).function_result_set()));
196
0
  }
197
198
0
  return UnknownValue(cel::Unknown(result_set->unknown_attributes(),
199
0
                                   result_set->unknown_function_results()));
200
0
}
201
202
0
UnknownValue AttributeUtility::CreateUnknownSet(cel::Attribute attr) const {
203
0
  return UnknownValue(cel::Unknown(AttributeSet({std::move(attr)})));
204
0
}
205
206
absl::StatusOr<ErrorValue> AttributeUtility::CreateMissingAttributeError(
207
0
    const cel::Attribute& attr) const {
208
0
  CEL_ASSIGN_OR_RETURN(std::string message, attr.AsString());
209
0
  return cel::ErrorValue(
210
0
      cel::runtime_internal::CreateMissingAttributeError(message));
211
0
}
212
213
UnknownValue AttributeUtility::CreateUnknownSet(
214
    const cel::FunctionDescriptor& fn_descriptor, int64_t expr_id,
215
0
    absl::Span<const cel::Value> args) const {
216
0
  return UnknownValue(
217
0
      cel::Unknown(FunctionResultSet(FunctionResult(fn_descriptor, expr_id))));
218
0
}
219
220
0
void AttributeUtility::Add(Accumulator& a, const cel::UnknownValue& v) const {
221
0
  a.attribute_set_.Add(v.attribute_set());
222
0
  a.function_result_set_.Add(v.function_result_set());
223
0
}
224
225
0
void AttributeUtility::Add(Accumulator& a, const AttributeTrail& attr) const {
226
0
  a.attribute_set_.Add(attr.attribute());
227
0
}
228
229
0
void Accumulator::Add(const UnknownValue& value) {
230
0
  unknown_present_ = true;
231
0
  parent_.Add(*this, value);
232
0
}
233
234
0
void Accumulator::Add(const AttributeTrail& attr) { parent_.Add(*this, attr); }
235
236
0
void Accumulator::MaybeAdd(const Value& v) {
237
0
  if (v.IsUnknown()) {
238
0
    Add(v.GetUnknown());
239
0
  }
240
0
}
241
242
0
void Accumulator::MaybeAdd(const Value& v, const AttributeTrail& attr) {
243
0
  if (v.IsUnknown()) {
244
0
    Add(v.GetUnknown());
245
0
  } else if (parent_.CheckForUnknown(attr, /*use_partial=*/true)) {
246
0
    Add(attr);
247
0
  }
248
0
}
249
250
0
bool Accumulator::IsEmpty() const {
251
0
  return !unknown_present_ && attribute_set_.empty() &&
252
0
         function_result_set_.empty();
253
0
}
254
255
0
cel::UnknownValue Accumulator::Build() && {
256
0
  return cel::UnknownValue(
257
0
      cel::Unknown(std::move(attribute_set_), std::move(function_result_set_)));
258
0
}
259
260
}  // namespace google::api::expr::runtime