Skip to content

Commit 25984e8

Browse files
CEL Dev Teamcopybara-github
authored andcommitted
Add the function AddProtoTypeMask to the type checker.
PiperOrigin-RevId: 820311481
1 parent cb9dc8a commit 25984e8

15 files changed

Lines changed: 1254 additions & 6 deletions

checker/internal/BUILD

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ cc_library(
6666
hdrs = ["type_check_env.h"],
6767
deps = [
6868
":descriptor_pool_type_introspector",
69+
":proto_type_mask",
70+
":proto_type_mask_registry",
6971
"//common:constant",
7072
"//common:container",
7173
"//common:decl",
@@ -76,6 +78,7 @@ cc_library(
7678
"@com_google_absl//absl/container:flat_hash_map",
7779
"@com_google_absl//absl/log:absl_check",
7880
"@com_google_absl//absl/memory",
81+
"@com_google_absl//absl/status",
7982
"@com_google_absl//absl/status:statusor",
8083
"@com_google_absl//absl/strings",
8184
"@com_google_absl//absl/strings:string_view",
@@ -129,6 +132,8 @@ cc_library(
129132
deps = [
130133
":format_type_name",
131134
":namespace_generator",
135+
":proto_type_mask",
136+
":proto_type_mask_registry",
132137
":type_check_env",
133138
":type_inference_context",
134139
"//checker:checker_options",
@@ -310,3 +315,88 @@ cc_test(
310315
"@com_google_absl//absl/types:optional",
311316
],
312317
)
318+
319+
cc_library(
320+
name = "field_path",
321+
srcs = ["field_path.cc"],
322+
hdrs = ["field_path.h"],
323+
deps = [
324+
"@com_google_absl//absl/strings",
325+
"@com_google_absl//absl/strings:str_format",
326+
"@com_google_absl//absl/strings:string_view",
327+
"@com_google_absl//absl/types:span",
328+
],
329+
)
330+
331+
cc_test(
332+
name = "field_path_test",
333+
srcs = ["field_path_test.cc"],
334+
deps = [
335+
":field_path",
336+
"//internal:testing",
337+
"@com_google_absl//absl/strings",
338+
],
339+
)
340+
341+
cc_library(
342+
name = "proto_type_mask",
343+
srcs = ["proto_type_mask.cc"],
344+
hdrs = ["proto_type_mask.h"],
345+
deps = [
346+
":field_path",
347+
"@com_google_absl//absl/container:btree",
348+
"@com_google_absl//absl/strings",
349+
],
350+
)
351+
352+
cc_test(
353+
name = "proto_type_mask_test",
354+
srcs = ["proto_type_mask_test.cc"],
355+
deps = [
356+
":field_path",
357+
":proto_type_mask",
358+
"//internal:testing",
359+
"@com_google_absl//absl/strings",
360+
],
361+
)
362+
363+
cc_library(
364+
name = "proto_type_mask_registry",
365+
srcs = ["proto_type_mask_registry.cc"],
366+
hdrs = ["proto_type_mask_registry.h"],
367+
deps = [
368+
":field_path",
369+
":proto_type_mask",
370+
"//common:type",
371+
"//internal:status_macros",
372+
"@com_google_absl//absl/base:nullability",
373+
"@com_google_absl//absl/container:btree",
374+
"@com_google_absl//absl/container:flat_hash_map",
375+
"@com_google_absl//absl/container:flat_hash_set",
376+
"@com_google_absl//absl/memory",
377+
"@com_google_absl//absl/status",
378+
"@com_google_absl//absl/status:statusor",
379+
"@com_google_absl//absl/strings",
380+
"@com_google_absl//absl/strings:string_view",
381+
"@com_google_absl//absl/types:optional",
382+
"@com_google_absl//absl/types:span",
383+
"@com_google_protobuf//:protobuf",
384+
],
385+
)
386+
387+
cc_test(
388+
name = "proto_type_mask_registry_test",
389+
srcs = ["proto_type_mask_registry_test.cc"],
390+
deps = [
391+
":proto_type_mask",
392+
":proto_type_mask_registry",
393+
"//internal:testing",
394+
"//internal:testing_descriptor_pool",
395+
"@com_google_absl//absl/container:flat_hash_map",
396+
"@com_google_absl//absl/container:flat_hash_set",
397+
"@com_google_absl//absl/status",
398+
"@com_google_absl//absl/status:status_matchers",
399+
"@com_google_absl//absl/strings",
400+
"@com_google_absl//absl/strings:string_view",
401+
],
402+
)

checker/internal/field_path.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2026 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 "checker/internal/field_path.h"
16+
17+
#include <string>
18+
19+
#include "absl/strings/str_join.h"
20+
#include "absl/strings/substitute.h"
21+
22+
namespace cel::checker_internal {
23+
24+
std::string FieldPath::DebugString() const {
25+
return absl::Substitute(
26+
"FieldPath { field path: '$0', field selection: {'$1'} }", path_,
27+
absl::StrJoin(field_selection_, "', '"));
28+
}
29+
30+
} // namespace cel::checker_internal

checker/internal/field_path.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2026 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+
#ifndef THIRD_PARTY_CEL_CPP_CHECKER_FIELD_PATH_H_
16+
#define THIRD_PARTY_CEL_CPP_CHECKER_FIELD_PATH_H_
17+
18+
#include <string>
19+
#include <utility>
20+
#include <vector>
21+
22+
#include "absl/strings/str_format.h"
23+
#include "absl/strings/str_split.h"
24+
#include "absl/strings/string_view.h"
25+
#include "absl/types/span.h"
26+
27+
namespace cel::checker_internal {
28+
29+
// Represents a single path within a FieldMask.
30+
class FieldPath {
31+
public:
32+
explicit FieldPath(std::string path)
33+
: path_(std::move(path)),
34+
field_selection_(absl::StrSplit(path_, kPathDelimiter)) {}
35+
36+
absl::string_view GetPath() const { return path_; }
37+
38+
absl::Span<const std::string> GetFieldSelection() const {
39+
return field_selection_;
40+
}
41+
42+
// Returns the first field name in the path.
43+
std::string GetFieldName() const { return field_selection_.front(); }
44+
45+
template <typename Sink>
46+
friend void AbslStringify(Sink& sink, const FieldPath& field_path) {
47+
absl::Format(&sink, "%v", field_path.DebugString());
48+
};
49+
50+
private:
51+
static constexpr char kPathDelimiter = '.';
52+
53+
std::string DebugString() const;
54+
55+
// The input path. For example: "f.b.d".
56+
std::string path_;
57+
// The list of nested field names in the path. For example: {"f", "b", "d"}.
58+
std::vector<std::string> field_selection_;
59+
};
60+
61+
inline bool operator==(const FieldPath& lhs, const FieldPath& rhs) {
62+
return lhs.GetFieldSelection() == rhs.GetFieldSelection();
63+
}
64+
65+
// Compares the field selections in the field paths.
66+
// This is only intended as an arbitrary ordering for a set.
67+
inline bool operator<(const FieldPath& lhs, const FieldPath& rhs) {
68+
return lhs.GetFieldSelection() < rhs.GetFieldSelection();
69+
}
70+
71+
} // namespace cel::checker_internal
72+
73+
#endif // THIRD_PARTY_CEL_CPP_CHECKER_FIELD_PATH_H_
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright 2026 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 "checker/internal/field_path.h"
16+
17+
#include "absl/strings/str_cat.h"
18+
#include "internal/testing.h"
19+
20+
namespace cel::checker_internal {
21+
namespace {
22+
23+
using ::testing::ElementsAre;
24+
25+
TEST(FieldPathTest, EmptyPathReturnsEmptyString) {
26+
FieldPath field_path("");
27+
EXPECT_EQ(field_path.GetPath(), "");
28+
EXPECT_THAT(field_path.GetFieldSelection(), ElementsAre(""));
29+
EXPECT_EQ(field_path.GetFieldName(), "");
30+
}
31+
32+
TEST(FieldPathTest, DelimiterPathReturnsEmptyStrings) {
33+
FieldPath field_path(".");
34+
EXPECT_EQ(field_path.GetPath(), ".");
35+
EXPECT_THAT(field_path.GetFieldSelection(), ElementsAre("", ""));
36+
EXPECT_EQ(field_path.GetFieldName(), "");
37+
}
38+
39+
TEST(FieldPathTest, FieldPathReturnsFields) {
40+
FieldPath field_path("resource.name.other_field");
41+
EXPECT_EQ(field_path.GetPath(), "resource.name.other_field");
42+
EXPECT_THAT(field_path.GetFieldSelection(),
43+
ElementsAre("resource", "name", "other_field"));
44+
EXPECT_EQ(field_path.GetFieldName(), "resource");
45+
}
46+
47+
TEST(FieldPathTest, AbslStringifyPrintsFieldSelection) {
48+
FieldPath field_path("resource.name");
49+
EXPECT_EQ(absl::StrCat(field_path),
50+
"FieldPath { field path: 'resource.name', field selection: "
51+
"{'resource', 'name'} }");
52+
}
53+
54+
TEST(FieldPathTest, EqualsComparesFieldSelectionAndReturnsTrue) {
55+
FieldPath field_path_1("resource.name");
56+
FieldPath field_path_2("resource.name");
57+
EXPECT_TRUE(field_path_1 == field_path_2);
58+
}
59+
60+
TEST(FieldPathTest, EqualsComparesFieldSelectionAndReturnsFalse) {
61+
FieldPath field_path_1("resource.name");
62+
FieldPath field_path_2("resource.type");
63+
EXPECT_FALSE(field_path_1 == field_path_2);
64+
}
65+
66+
TEST(FieldPathTest, LessThanComparesFieldSelectionAndReturnsTrue) {
67+
FieldPath field_path_1("resource.name");
68+
FieldPath field_path_2("resource.type");
69+
EXPECT_TRUE(field_path_1 < field_path_2);
70+
}
71+
72+
TEST(FieldPathTest, LessThanComparesFieldSelectionAndReturnsFalse) {
73+
FieldPath field_path_1("resource.name");
74+
FieldPath field_path_2("resource.name");
75+
EXPECT_FALSE(field_path_1 < field_path_2);
76+
}
77+
78+
} // namespace
79+
} // namespace cel::checker_internal
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2026 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 "checker/internal/proto_type_mask.h"
16+
17+
#include <string>
18+
#include <vector>
19+
20+
#include "absl/strings/str_join.h"
21+
#include "absl/strings/substitute.h"
22+
#include "checker/internal/field_path.h"
23+
24+
namespace cel::checker_internal {
25+
26+
std::string ProtoTypeMask::DebugString() const {
27+
// Represent each FieldPath by its path because it is easiest to read.
28+
std::vector<std::string> paths;
29+
paths.reserve(field_paths_.size());
30+
for (const FieldPath& field_path : field_paths_) {
31+
paths.emplace_back(field_path.GetPath());
32+
}
33+
return absl::Substitute(
34+
"ProtoTypeMask { type name: '$0', field paths: { '$1' } }", type_name_,
35+
absl::StrJoin(paths, "', '"));
36+
}
37+
38+
} // namespace cel::checker_internal

0 commit comments

Comments
 (0)