Coverage Report

Created: 2026-10-09 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/common/values/parsed_message_value.cc
Line
Count
Source
1
// Copyright 2024 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "common/values/parsed_message_value.h"
16
17
#include <cstdint>
18
#include <limits>
19
#include <string>
20
#include <type_traits>
21
#include <utility>
22
#include <vector>
23
24
#include "google/protobuf/empty.pb.h"
25
#include "absl/base/nullability.h"
26
#include "absl/base/optimization.h"
27
#include "absl/log/absl_check.h"
28
#include "absl/status/status.h"
29
#include "absl/status/statusor.h"
30
#include "absl/strings/str_cat.h"
31
#include "absl/strings/string_view.h"
32
#include "absl/types/optional.h"
33
#include "absl/types/span.h"
34
#include "base/attribute.h"
35
#include "common/memory.h"
36
#include "common/value.h"
37
#include "common/values/values.h"
38
#include "extensions/protobuf/internal/qualify.h"
39
#include "internal/empty_descriptors.h"
40
#include "internal/json.h"
41
#include "internal/message_equality.h"
42
#include "internal/status_macros.h"
43
#include "runtime/runtime_options.h"
44
#include "google/protobuf/arena.h"
45
#include "google/protobuf/descriptor.h"
46
#include "google/protobuf/io/zero_copy_stream.h"
47
#include "google/protobuf/message.h"
48
#include "google/protobuf/message_lite.h"
49
50
namespace cel {
51
52
namespace {
53
54
template <typename T>
55
std::enable_if_t<std::is_base_of_v<google::protobuf::Message, T>,
56
                 const google::protobuf::Message* absl_nonnull>
57
0
EmptyParsedMessageValue() {
58
0
  return &T::default_instance();
59
0
}
60
61
template <typename T>
62
std::enable_if_t<
63
    std::conjunction_v<std::is_base_of<google::protobuf::MessageLite, T>,
64
                       std::negation<std::is_base_of<google::protobuf::Message, T>>>,
65
    const google::protobuf::Message* absl_nonnull>
66
EmptyParsedMessageValue() {
67
  return internal::GetEmptyDefaultInstance();
68
}
69
70
}  // namespace
71
72
ParsedMessageValue::ParsedMessageValue()
73
0
    : value_(EmptyParsedMessageValue<google::protobuf::Empty>()),
74
0
      arena_(nullptr) {}
75
76
0
bool ParsedMessageValue::IsZeroValue() const {
77
0
  const auto* reflection = GetReflection();
78
0
  if (!reflection->GetUnknownFields(*value_).empty()) {
79
0
    return false;
80
0
  }
81
0
  std::vector<const google::protobuf::FieldDescriptor*> fields;
82
0
  reflection->ListFields(*value_, &fields);
83
0
  return fields.empty();
84
0
}
85
86
0
std::string ParsedMessageValue::DebugString() const {
87
0
  return absl::StrCat(*value_);
88
0
}
89
90
absl::Status ParsedMessageValue::SerializeTo(
91
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
92
    google::protobuf::MessageFactory* absl_nonnull message_factory,
93
0
    google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const {
94
0
  ABSL_DCHECK(descriptor_pool != nullptr);
95
0
  ABSL_DCHECK(message_factory != nullptr);
96
0
  ABSL_DCHECK(output != nullptr);
97
98
0
  if (!value_->SerializePartialToZeroCopyStream(output)) {
99
0
    return absl::UnknownError(
100
0
        absl::StrCat("failed to serialize message: ", value_->GetTypeName()));
101
0
  }
102
0
  return absl::OkStatus();
103
0
}
104
105
absl::Status ParsedMessageValue::ConvertToJson(
106
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
107
    google::protobuf::MessageFactory* absl_nonnull message_factory,
108
0
    google::protobuf::Message* absl_nonnull json) const {
109
0
  ABSL_DCHECK(descriptor_pool != nullptr);
110
0
  ABSL_DCHECK(message_factory != nullptr);
111
0
  ABSL_DCHECK(json != nullptr);
112
0
  ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(),
113
0
                 google::protobuf::Descriptor::WELLKNOWNTYPE_VALUE);
114
115
0
  return internal::MessageToJson(*value_, descriptor_pool, message_factory,
116
0
                                 json);
117
0
}
118
119
absl::Status ParsedMessageValue::ConvertToJsonObject(
120
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
121
    google::protobuf::MessageFactory* absl_nonnull message_factory,
122
0
    google::protobuf::Message* absl_nonnull json) const {
123
0
  ABSL_DCHECK(descriptor_pool != nullptr);
124
0
  ABSL_DCHECK(message_factory != nullptr);
125
0
  ABSL_DCHECK(json != nullptr);
126
0
  ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(),
127
0
                 google::protobuf::Descriptor::WELLKNOWNTYPE_STRUCT);
128
129
0
  return internal::MessageToJson(*value_, descriptor_pool, message_factory,
130
0
                                 json);
131
0
}
132
133
absl::Status ParsedMessageValue::Equal(
134
    const Value& other,
135
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
136
    google::protobuf::MessageFactory* absl_nonnull message_factory,
137
28.7k
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
138
28.7k
  ABSL_DCHECK(descriptor_pool != nullptr);
139
28.7k
  ABSL_DCHECK(message_factory != nullptr);
140
28.7k
  ABSL_DCHECK(arena != nullptr);
141
28.7k
  ABSL_DCHECK(result != nullptr);
142
143
28.7k
  if (auto other_message = other.AsParsedMessage(); other_message) {
144
28.5k
    CEL_ASSIGN_OR_RETURN(
145
28.5k
        auto equal, internal::MessageEquals(*value_, **other_message,
146
28.5k
                                            descriptor_pool, message_factory));
147
28.5k
    *result = BoolValue(equal);
148
28.5k
    return absl::OkStatus();
149
28.5k
  }
150
222
  if (auto other_struct = other.AsStruct(); other_struct) {
151
0
    return common_internal::StructValueEqual(StructValue(*this), *other_struct,
152
0
                                             descriptor_pool, message_factory,
153
0
                                             arena, result);
154
0
  }
155
222
  *result = BoolValue(false);
156
222
  return absl::OkStatus();
157
222
}
158
159
ParsedMessageValue ParsedMessageValue::Clone(
160
467k
    google::protobuf::Arena* absl_nonnull arena) const {
161
467k
  ABSL_DCHECK(arena != nullptr);
162
163
467k
  if (arena_ == arena) {
164
467k
    return *this;
165
467k
  }
166
0
  auto* cloned = value_->New(arena);
167
0
  cloned->CopyFrom(*value_);
168
0
  return ParsedMessageValue(cloned, arena);
169
467k
}
170
171
absl::Status ParsedMessageValue::GetFieldByName(
172
    absl::string_view name, ProtoWrapperTypeOptions unboxing_options,
173
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
174
    google::protobuf::MessageFactory* absl_nonnull message_factory,
175
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
176
0
  ABSL_DCHECK(descriptor_pool != nullptr);
177
0
  ABSL_DCHECK(message_factory != nullptr);
178
0
  ABSL_DCHECK(arena != nullptr);
179
0
  ABSL_DCHECK(result != nullptr);
180
181
0
  const auto* descriptor = GetDescriptor();
182
0
  const auto* field = descriptor->FindFieldByName(name);
183
0
  if (field == nullptr) {
184
0
    field = descriptor->file()->pool()->FindExtensionByPrintableName(descriptor,
185
0
                                                                     name);
186
0
    if (field == nullptr) {
187
0
      *result = NoSuchFieldError(name, arena);
188
0
      return absl::OkStatus();
189
0
    }
190
0
  }
191
0
  return GetField(field, unboxing_options, descriptor_pool, message_factory,
192
0
                  arena, result);
193
0
}
194
195
absl::Status ParsedMessageValue::GetFieldByNumber(
196
    int64_t number, ProtoWrapperTypeOptions unboxing_options,
197
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
198
    google::protobuf::MessageFactory* absl_nonnull message_factory,
199
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
200
0
  ABSL_DCHECK(descriptor_pool != nullptr);
201
0
  ABSL_DCHECK(message_factory != nullptr);
202
0
  ABSL_DCHECK(arena != nullptr);
203
0
  ABSL_DCHECK(result != nullptr);
204
205
0
  const auto* descriptor = GetDescriptor();
206
0
  if (number < std::numeric_limits<int32_t>::min() ||
207
0
      number > std::numeric_limits<int32_t>::max()) {
208
0
    *result = NoSuchFieldError(absl::StrCat(number), arena);
209
0
    return absl::OkStatus();
210
0
  }
211
0
  const auto* field = descriptor->FindFieldByNumber(static_cast<int>(number));
212
0
  if (field == nullptr) {
213
0
    *result = NoSuchFieldError(absl::StrCat(number), arena);
214
0
    return absl::OkStatus();
215
0
  }
216
0
  return GetField(field, unboxing_options, descriptor_pool, message_factory,
217
0
                  arena, result);
218
0
}
219
220
absl::StatusOr<bool> ParsedMessageValue::HasFieldByName(
221
0
    absl::string_view name) const {
222
0
  const auto* descriptor = GetDescriptor();
223
0
  const auto* field = descriptor->FindFieldByName(name);
224
0
  if (field == nullptr) {
225
0
    field = descriptor->file()->pool()->FindExtensionByPrintableName(descriptor,
226
0
                                                                     name);
227
0
    if (field == nullptr) {
228
0
      return common_internal::MakeNoSuchFieldError(name);
229
0
    }
230
0
  }
231
0
  return HasField(field);
232
0
}
233
234
absl::StatusOr<bool> ParsedMessageValue::HasFieldByNumber(
235
0
    int64_t number) const {
236
0
  const auto* descriptor = GetDescriptor();
237
0
  if (number < std::numeric_limits<int32_t>::min() ||
238
0
      number > std::numeric_limits<int32_t>::max()) {
239
0
    return common_internal::MakeNoSuchFieldError(absl::StrCat(number));
240
0
  }
241
0
  const auto* field = descriptor->FindFieldByNumber(static_cast<int>(number));
242
0
  if (field == nullptr) {
243
0
    return common_internal::MakeNoSuchFieldError(absl::StrCat(number));
244
0
  }
245
0
  return HasField(field);
246
0
}
247
248
absl::Status ParsedMessageValue::ForEachField(
249
    ForEachFieldCallback callback,
250
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
251
    google::protobuf::MessageFactory* absl_nonnull message_factory,
252
0
    google::protobuf::Arena* absl_nonnull arena) const {
253
0
  ABSL_DCHECK(descriptor_pool != nullptr);
254
0
  ABSL_DCHECK(message_factory != nullptr);
255
0
  ABSL_DCHECK(arena != nullptr);
256
257
0
  std::vector<const google::protobuf::FieldDescriptor*> fields;
258
0
  const auto* reflection = GetReflection();
259
0
  reflection->ListFields(*value_, &fields);
260
0
  for (const auto* field : fields) {
261
0
    auto value = Value::WrapField(value_, field, descriptor_pool,
262
0
                                  message_factory, arena);
263
0
    CEL_ASSIGN_OR_RETURN(auto ok, callback(field->name(), value));
264
0
    if (!ok) {
265
0
      break;
266
0
    }
267
0
  }
268
0
  return absl::OkStatus();
269
0
}
270
271
namespace {
272
273
class ParsedMessageValueQualifyState final
274
    : public extensions::protobuf_internal::ProtoQualifyState {
275
 public:
276
  ParsedMessageValueQualifyState(
277
      const google::protobuf::Message* absl_nonnull message,
278
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
279
      google::protobuf::MessageFactory* absl_nonnull message_factory,
280
      google::protobuf::Arena* absl_nonnull arena, bool unsafe)
281
0
      : ProtoQualifyState(message, message->GetDescriptor(),
282
0
                          message->GetReflection()),
283
0
        descriptor_pool_(descriptor_pool),
284
0
        message_factory_(message_factory),
285
0
        arena_(arena),
286
0
        unsafe_(unsafe) {}
287
288
0
  absl::optional<Value>& result() { return result_; }
289
290
 private:
291
0
  void SetResultFromError(absl::Status status, cel::MemoryManagerRef) override {
292
0
    result_ = ErrorValue::From(std::move(status), arena_);
293
0
  }
294
295
0
  void SetResultFromBool(bool value) override { result_ = BoolValue(value); }
296
297
  // When `unsafe_` is set, the qualified message is externally managed (see
298
  // `UnsafeParsedMessageValue()`), so borrow field values instead of copying
299
  // them onto `arena_`. This matches `ParsedMessageValue::GetField()`.
300
  absl::Status SetResultFromField(const google::protobuf::Message* message,
301
                                  const google::protobuf::FieldDescriptor* field,
302
                                  ProtoWrapperTypeOptions unboxing_option,
303
0
                                  cel::MemoryManagerRef) override {
304
0
    result_ =
305
0
        unsafe_
306
0
            ? Value::WrapFieldUnsafe(unboxing_option, message, field,
307
0
                                     descriptor_pool_, message_factory_, arena_)
308
0
            : Value::WrapField(unboxing_option, message, field,
309
0
                               descriptor_pool_, message_factory_, arena_);
310
0
    return absl::OkStatus();
311
0
  }
312
313
  absl::Status SetResultFromRepeatedField(const google::protobuf::Message* message,
314
                                          const google::protobuf::FieldDescriptor* field,
315
                                          int index,
316
0
                                          cel::MemoryManagerRef) override {
317
0
    result_ = unsafe_ ? Value::WrapRepeatedFieldUnsafe(index, message, field,
318
0
                                                       descriptor_pool_,
319
0
                                                       message_factory_, arena_)
320
0
                      : Value::WrapRepeatedField(index, message, field,
321
0
                                                 descriptor_pool_,
322
0
                                                 message_factory_, arena_);
323
0
    return absl::OkStatus();
324
0
  }
325
326
  absl::Status SetResultFromMapField(const google::protobuf::Message* message,
327
                                     const google::protobuf::FieldDescriptor* field,
328
                                     const google::protobuf::MapValueConstRef& value,
329
0
                                     cel::MemoryManagerRef) override {
330
0
    result_ = unsafe_ ? Value::WrapMapFieldValueUnsafe(value, message, field,
331
0
                                                       descriptor_pool_,
332
0
                                                       message_factory_, arena_)
333
0
                      : Value::WrapMapFieldValue(value, message, field,
334
0
                                                 descriptor_pool_,
335
0
                                                 message_factory_, arena_);
336
0
    return absl::OkStatus();
337
0
  }
338
339
  const google::protobuf::DescriptorPool* absl_nonnull const descriptor_pool_;
340
  google::protobuf::MessageFactory* absl_nonnull const message_factory_;
341
  google::protobuf::Arena* absl_nonnull const arena_;
342
  const bool unsafe_;
343
  absl::optional<Value> result_;
344
};
345
346
}  // namespace
347
348
absl::Status ParsedMessageValue::Qualify(
349
    absl::Span<const SelectQualifier> qualifiers, bool presence_test,
350
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
351
    google::protobuf::MessageFactory* absl_nonnull message_factory,
352
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result,
353
0
    int* absl_nonnull count) const {
354
0
  ABSL_DCHECK(!qualifiers.empty());
355
0
  ABSL_DCHECK(descriptor_pool != nullptr);
356
0
  ABSL_DCHECK(message_factory != nullptr);
357
0
  ABSL_DCHECK(arena != nullptr);
358
0
  ABSL_DCHECK(result != nullptr);
359
0
  ABSL_DCHECK(count != nullptr);
360
361
0
  if (ABSL_PREDICT_FALSE(qualifiers.empty())) {
362
0
    return absl::InvalidArgumentError("invalid select qualifier path.");
363
0
  }
364
0
  ParsedMessageValueQualifyState qualify_state(
365
0
      value_, descriptor_pool, message_factory, arena, is_unsafe());
366
0
  for (int i = 0; i < qualifiers.size() - 1; i++) {
367
0
    const auto& qualifier = qualifiers[i];
368
0
    CEL_RETURN_IF_ERROR(qualify_state.ApplySelectQualifier(
369
0
        qualifier, MemoryManagerRef::Pooling(arena)));
370
0
    if (qualify_state.result().has_value()) {
371
0
      *result = std::move(qualify_state.result()).value();
372
0
      *count = result->Is<ErrorValue>() ? -1 : i + 1;
373
0
      return absl::OkStatus();
374
0
    }
375
0
  }
376
0
  const auto& last_qualifier = qualifiers.back();
377
0
  if (presence_test) {
378
0
    CEL_RETURN_IF_ERROR(qualify_state.ApplyLastQualifierHas(
379
0
        last_qualifier, MemoryManagerRef::Pooling(arena)));
380
0
  } else {
381
0
    CEL_RETURN_IF_ERROR(qualify_state.ApplyLastQualifierGet(
382
0
        last_qualifier, MemoryManagerRef::Pooling(arena)));
383
0
  }
384
0
  *result = std::move(qualify_state.result()).value();
385
0
  *count = -1;
386
0
  return absl::OkStatus();
387
0
}
388
389
absl::Status ParsedMessageValue::GetField(
390
    const google::protobuf::FieldDescriptor* absl_nonnull field,
391
    ProtoWrapperTypeOptions unboxing_options,
392
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
393
    google::protobuf::MessageFactory* absl_nonnull message_factory,
394
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
395
0
  ABSL_DCHECK(field != nullptr);
396
0
  ABSL_DCHECK(descriptor_pool != nullptr);
397
0
  ABSL_DCHECK(message_factory != nullptr);
398
0
  ABSL_DCHECK(arena != nullptr);
399
0
  ABSL_DCHECK(result != nullptr);
400
401
0
  if (is_unsafe()) {
402
0
    *result = Value::WrapFieldUnsafe(unboxing_options, value_, field,
403
0
                                     descriptor_pool, message_factory, arena);
404
0
  } else {
405
0
    *result = Value::WrapField(unboxing_options, value_, field, descriptor_pool,
406
0
                               message_factory, arena);
407
0
  }
408
0
  return absl::OkStatus();
409
0
}
410
411
bool ParsedMessageValue::HasField(
412
0
    const google::protobuf::FieldDescriptor* absl_nonnull field) const {
413
0
  ABSL_DCHECK(field != nullptr);
414
415
0
  const auto* reflection = GetReflection();
416
0
  if (field->is_map() || field->is_repeated()) {
417
0
    return reflection->FieldSize(*value_, field) > 0;
418
0
  }
419
0
  return reflection->HasField(*value_, field);
420
0
}
421
422
}  // namespace cel