Coverage Report

Created: 2026-09-03 06:30

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 "internal/well_known_types.h"
44
#include "runtime/runtime_options.h"
45
#include "google/protobuf/arena.h"
46
#include "google/protobuf/descriptor.h"
47
#include "google/protobuf/io/zero_copy_stream.h"
48
#include "google/protobuf/message.h"
49
#include "google/protobuf/message_lite.h"
50
51
namespace cel {
52
53
namespace {
54
55
template <typename T>
56
std::enable_if_t<std::is_base_of_v<google::protobuf::Message, T>,
57
                 const google::protobuf::Message* absl_nonnull>
58
0
EmptyParsedMessageValue() {
59
0
  return &T::default_instance();
60
0
}
61
62
template <typename T>
63
std::enable_if_t<
64
    std::conjunction_v<std::is_base_of<google::protobuf::MessageLite, T>,
65
                       std::negation<std::is_base_of<google::protobuf::Message, T>>>,
66
    const google::protobuf::Message* absl_nonnull>
67
EmptyParsedMessageValue() {
68
  return internal::GetEmptyDefaultInstance();
69
}
70
71
}  // namespace
72
73
ParsedMessageValue::ParsedMessageValue()
74
0
    : value_(EmptyParsedMessageValue<google::protobuf::Empty>()),
75
0
      arena_(nullptr) {}
76
77
0
bool ParsedMessageValue::IsZeroValue() const {
78
0
  const auto* reflection = GetReflection();
79
0
  if (!reflection->GetUnknownFields(*value_).empty()) {
80
0
    return false;
81
0
  }
82
0
  std::vector<const google::protobuf::FieldDescriptor*> fields;
83
0
  reflection->ListFields(*value_, &fields);
84
0
  return fields.empty();
85
0
}
86
87
0
std::string ParsedMessageValue::DebugString() const {
88
0
  return absl::StrCat(*value_);
89
0
}
90
91
absl::Status ParsedMessageValue::SerializeTo(
92
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
93
    google::protobuf::MessageFactory* absl_nonnull message_factory,
94
0
    google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const {
95
0
  ABSL_DCHECK(descriptor_pool != nullptr);
96
0
  ABSL_DCHECK(message_factory != nullptr);
97
0
  ABSL_DCHECK(output != nullptr);
98
99
0
  if (!value_->SerializePartialToZeroCopyStream(output)) {
100
0
    return absl::UnknownError(
101
0
        absl::StrCat("failed to serialize message: ", value_->GetTypeName()));
102
0
  }
103
0
  return absl::OkStatus();
104
0
}
105
106
absl::Status ParsedMessageValue::ConvertToJson(
107
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
108
    google::protobuf::MessageFactory* absl_nonnull message_factory,
109
0
    google::protobuf::Message* absl_nonnull json) const {
110
0
  ABSL_DCHECK(descriptor_pool != nullptr);
111
0
  ABSL_DCHECK(message_factory != nullptr);
112
0
  ABSL_DCHECK(json != nullptr);
113
0
  ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(),
114
0
                 google::protobuf::Descriptor::WELLKNOWNTYPE_VALUE);
115
116
0
  return internal::MessageToJson(*value_, descriptor_pool, message_factory,
117
0
                                 json);
118
0
}
119
120
absl::Status ParsedMessageValue::ConvertToJsonObject(
121
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
122
    google::protobuf::MessageFactory* absl_nonnull message_factory,
123
0
    google::protobuf::Message* absl_nonnull json) const {
124
0
  ABSL_DCHECK(descriptor_pool != nullptr);
125
0
  ABSL_DCHECK(message_factory != nullptr);
126
0
  ABSL_DCHECK(json != nullptr);
127
0
  ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(),
128
0
                 google::protobuf::Descriptor::WELLKNOWNTYPE_STRUCT);
129
130
0
  return internal::MessageToJson(*value_, descriptor_pool, message_factory,
131
0
                                 json);
132
0
}
133
134
absl::Status ParsedMessageValue::Equal(
135
    const Value& other,
136
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
137
    google::protobuf::MessageFactory* absl_nonnull message_factory,
138
19.1k
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
139
19.1k
  ABSL_DCHECK(descriptor_pool != nullptr);
140
19.1k
  ABSL_DCHECK(message_factory != nullptr);
141
19.1k
  ABSL_DCHECK(arena != nullptr);
142
19.1k
  ABSL_DCHECK(result != nullptr);
143
144
19.1k
  if (auto other_message = other.AsParsedMessage(); other_message) {
145
19.0k
    CEL_ASSIGN_OR_RETURN(
146
19.0k
        auto equal, internal::MessageEquals(*value_, **other_message,
147
19.0k
                                            descriptor_pool, message_factory));
148
19.0k
    *result = BoolValue(equal);
149
19.0k
    return absl::OkStatus();
150
19.0k
  }
151
73
  if (auto other_struct = other.AsStruct(); other_struct) {
152
0
    return common_internal::StructValueEqual(StructValue(*this), *other_struct,
153
0
                                             descriptor_pool, message_factory,
154
0
                                             arena, result);
155
0
  }
156
73
  *result = BoolValue(false);
157
73
  return absl::OkStatus();
158
73
}
159
160
ParsedMessageValue ParsedMessageValue::Clone(
161
244k
    google::protobuf::Arena* absl_nonnull arena) const {
162
244k
  ABSL_DCHECK(arena != nullptr);
163
164
244k
  if (arena_ == arena) {
165
244k
    return *this;
166
244k
  }
167
0
  auto* cloned = value_->New(arena);
168
0
  cloned->CopyFrom(*value_);
169
0
  return ParsedMessageValue(cloned, arena);
170
244k
}
171
172
absl::Status ParsedMessageValue::GetFieldByName(
173
    absl::string_view name, ProtoWrapperTypeOptions unboxing_options,
174
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
175
    google::protobuf::MessageFactory* absl_nonnull message_factory,
176
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
177
0
  ABSL_DCHECK(descriptor_pool != nullptr);
178
0
  ABSL_DCHECK(message_factory != nullptr);
179
0
  ABSL_DCHECK(arena != nullptr);
180
0
  ABSL_DCHECK(result != nullptr);
181
182
0
  const auto* descriptor = GetDescriptor();
183
0
  const auto* field = descriptor->FindFieldByName(name);
184
0
  if (field == nullptr) {
185
0
    field = descriptor->file()->pool()->FindExtensionByPrintableName(descriptor,
186
0
                                                                     name);
187
0
    if (field == nullptr) {
188
0
      *result = NoSuchFieldError(name);
189
0
      return absl::OkStatus();
190
0
    }
191
0
  }
192
0
  return GetField(field, unboxing_options, descriptor_pool, message_factory,
193
0
                  arena, result);
194
0
}
195
196
absl::Status ParsedMessageValue::GetFieldByNumber(
197
    int64_t number, ProtoWrapperTypeOptions unboxing_options,
198
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
199
    google::protobuf::MessageFactory* absl_nonnull message_factory,
200
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
201
0
  ABSL_DCHECK(descriptor_pool != nullptr);
202
0
  ABSL_DCHECK(message_factory != nullptr);
203
0
  ABSL_DCHECK(arena != nullptr);
204
0
  ABSL_DCHECK(result != nullptr);
205
206
0
  const auto* descriptor = GetDescriptor();
207
0
  if (number < std::numeric_limits<int32_t>::min() ||
208
0
      number > std::numeric_limits<int32_t>::max()) {
209
0
    *result = NoSuchFieldError(absl::StrCat(number));
210
0
    return absl::OkStatus();
211
0
  }
212
0
  const auto* field = descriptor->FindFieldByNumber(static_cast<int>(number));
213
0
  if (field == nullptr) {
214
0
    *result = NoSuchFieldError(absl::StrCat(number));
215
0
    return absl::OkStatus();
216
0
  }
217
0
  return GetField(field, unboxing_options, descriptor_pool, message_factory,
218
0
                  arena, result);
219
0
}
220
221
absl::StatusOr<bool> ParsedMessageValue::HasFieldByName(
222
0
    absl::string_view name) const {
223
0
  const auto* descriptor = GetDescriptor();
224
0
  const auto* field = descriptor->FindFieldByName(name);
225
0
  if (field == nullptr) {
226
0
    field = descriptor->file()->pool()->FindExtensionByPrintableName(descriptor,
227
0
                                                                     name);
228
0
    if (field == nullptr) {
229
0
      return NoSuchFieldError(name).NativeValue();
230
0
    }
231
0
  }
232
0
  return HasField(field);
233
0
}
234
235
absl::StatusOr<bool> ParsedMessageValue::HasFieldByNumber(
236
0
    int64_t number) const {
237
0
  const auto* descriptor = GetDescriptor();
238
0
  if (number < std::numeric_limits<int32_t>::min() ||
239
0
      number > std::numeric_limits<int32_t>::max()) {
240
0
    return NoSuchFieldError(absl::StrCat(number)).NativeValue();
241
0
  }
242
0
  const auto* field = descriptor->FindFieldByNumber(static_cast<int>(number));
243
0
  if (field == nullptr) {
244
0
    return NoSuchFieldError(absl::StrCat(number)).NativeValue();
245
0
  }
246
0
  return HasField(field);
247
0
}
248
249
absl::Status ParsedMessageValue::ForEachField(
250
    ForEachFieldCallback callback,
251
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
252
    google::protobuf::MessageFactory* absl_nonnull message_factory,
253
0
    google::protobuf::Arena* absl_nonnull arena) const {
254
0
  ABSL_DCHECK(descriptor_pool != nullptr);
255
0
  ABSL_DCHECK(message_factory != nullptr);
256
0
  ABSL_DCHECK(arena != nullptr);
257
258
0
  std::vector<const google::protobuf::FieldDescriptor*> fields;
259
0
  const auto* reflection = GetReflection();
260
0
  reflection->ListFields(*value_, &fields);
261
0
  for (const auto* field : fields) {
262
0
    auto value = Value::WrapField(value_, field, descriptor_pool,
263
0
                                  message_factory, arena);
264
0
    CEL_ASSIGN_OR_RETURN(auto ok, callback(field->name(), value));
265
0
    if (!ok) {
266
0
      break;
267
0
    }
268
0
  }
269
0
  return absl::OkStatus();
270
0
}
271
272
namespace {
273
274
class ParsedMessageValueQualifyState final
275
    : public extensions::protobuf_internal::ProtoQualifyState {
276
 public:
277
  ParsedMessageValueQualifyState(
278
      const google::protobuf::Message* absl_nonnull message,
279
      const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
280
      google::protobuf::MessageFactory* absl_nonnull message_factory,
281
      google::protobuf::Arena* absl_nonnull arena)
282
0
      : ProtoQualifyState(message, message->GetDescriptor(),
283
0
                          message->GetReflection()),
284
0
        descriptor_pool_(descriptor_pool),
285
0
        message_factory_(message_factory),
286
0
        arena_(arena) {}
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(std::move(status));
293
0
  }
294
295
0
  void SetResultFromBool(bool value) override { result_ = BoolValue(value); }
296
297
  absl::Status SetResultFromField(const google::protobuf::Message* message,
298
                                  const google::protobuf::FieldDescriptor* field,
299
                                  ProtoWrapperTypeOptions unboxing_option,
300
0
                                  cel::MemoryManagerRef) override {
301
0
    result_ = Value::WrapField(unboxing_option, message, field,
302
0
                               descriptor_pool_, message_factory_, arena_);
303
0
    return absl::OkStatus();
304
0
  }
305
306
  absl::Status SetResultFromRepeatedField(const google::protobuf::Message* message,
307
                                          const google::protobuf::FieldDescriptor* field,
308
                                          int index,
309
0
                                          cel::MemoryManagerRef) override {
310
0
    result_ = Value::WrapRepeatedField(index, message, field, descriptor_pool_,
311
0
                                       message_factory_, arena_);
312
0
    return absl::OkStatus();
313
0
  }
314
315
  absl::Status SetResultFromMapField(const google::protobuf::Message* message,
316
                                     const google::protobuf::FieldDescriptor* field,
317
                                     const google::protobuf::MapValueConstRef& value,
318
0
                                     cel::MemoryManagerRef) override {
319
0
    result_ = Value::WrapMapFieldValue(value, message, field, descriptor_pool_,
320
0
                                       message_factory_, arena_);
321
0
    return absl::OkStatus();
322
0
  }
323
324
  const google::protobuf::DescriptorPool* absl_nonnull const descriptor_pool_;
325
  google::protobuf::MessageFactory* absl_nonnull const message_factory_;
326
  google::protobuf::Arena* absl_nonnull const arena_;
327
  absl::optional<Value> result_;
328
};
329
330
}  // namespace
331
332
absl::Status ParsedMessageValue::Qualify(
333
    absl::Span<const SelectQualifier> qualifiers, bool presence_test,
334
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
335
    google::protobuf::MessageFactory* absl_nonnull message_factory,
336
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result,
337
0
    int* absl_nonnull count) const {
338
0
  ABSL_DCHECK(!qualifiers.empty());
339
0
  ABSL_DCHECK(descriptor_pool != nullptr);
340
0
  ABSL_DCHECK(message_factory != nullptr);
341
0
  ABSL_DCHECK(arena != nullptr);
342
0
  ABSL_DCHECK(result != nullptr);
343
0
  ABSL_DCHECK(count != nullptr);
344
345
0
  if (ABSL_PREDICT_FALSE(qualifiers.empty())) {
346
0
    return absl::InvalidArgumentError("invalid select qualifier path.");
347
0
  }
348
0
  ParsedMessageValueQualifyState qualify_state(value_, descriptor_pool,
349
0
                                               message_factory, arena);
350
0
  for (int i = 0; i < qualifiers.size() - 1; i++) {
351
0
    const auto& qualifier = qualifiers[i];
352
0
    CEL_RETURN_IF_ERROR(qualify_state.ApplySelectQualifier(
353
0
        qualifier, MemoryManagerRef::Pooling(arena)));
354
0
    if (qualify_state.result().has_value()) {
355
0
      *result = std::move(qualify_state.result()).value();
356
0
      *count = result->Is<ErrorValue>() ? -1 : i + 1;
357
0
      return absl::OkStatus();
358
0
    }
359
0
  }
360
0
  const auto& last_qualifier = qualifiers.back();
361
0
  if (presence_test) {
362
0
    CEL_RETURN_IF_ERROR(qualify_state.ApplyLastQualifierHas(
363
0
        last_qualifier, MemoryManagerRef::Pooling(arena)));
364
0
  } else {
365
0
    CEL_RETURN_IF_ERROR(qualify_state.ApplyLastQualifierGet(
366
0
        last_qualifier, MemoryManagerRef::Pooling(arena)));
367
0
  }
368
0
  *result = std::move(qualify_state.result()).value();
369
0
  *count = -1;
370
0
  return absl::OkStatus();
371
0
}
372
373
absl::Status ParsedMessageValue::GetField(
374
    const google::protobuf::FieldDescriptor* absl_nonnull field,
375
    ProtoWrapperTypeOptions unboxing_options,
376
    const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool,
377
    google::protobuf::MessageFactory* absl_nonnull message_factory,
378
0
    google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const {
379
0
  ABSL_DCHECK(field != nullptr);
380
0
  ABSL_DCHECK(descriptor_pool != nullptr);
381
0
  ABSL_DCHECK(message_factory != nullptr);
382
0
  ABSL_DCHECK(arena != nullptr);
383
0
  ABSL_DCHECK(result != nullptr);
384
385
0
  if (is_unsafe()) {
386
0
    *result = Value::WrapFieldUnsafe(unboxing_options, value_, field,
387
0
                                     descriptor_pool, message_factory, arena);
388
0
  } else {
389
0
    *result = Value::WrapField(unboxing_options, value_, field, descriptor_pool,
390
0
                               message_factory, arena);
391
0
  }
392
0
  return absl::OkStatus();
393
0
}
394
395
bool ParsedMessageValue::HasField(
396
0
    const google::protobuf::FieldDescriptor* absl_nonnull field) const {
397
0
  ABSL_DCHECK(field != nullptr);
398
399
0
  const auto* reflection = GetReflection();
400
0
  if (field->is_map() || field->is_repeated()) {
401
0
    return reflection->FieldSize(*value_, field) > 0;
402
0
  }
403
0
  return reflection->HasField(*value_, field);
404
0
}
405
406
}  // namespace cel