Skip to content

Commit 1ca513f

Browse files
dmitriplotnikovcopybara-github
authored andcommitted
Add signature generation functions for types and function overloads
PiperOrigin-RevId: 904826666
1 parent 0341704 commit 1ca513f

9 files changed

Lines changed: 580 additions & 198 deletions

File tree

common/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ cc_library(
114114
":constant",
115115
":type",
116116
":type_kind",
117+
"//common/internal:signature",
117118
"//internal:status_macros",
118119
"@com_google_absl//absl/algorithm:container",
119120
"@com_google_absl//absl/base:core_headers",

common/decl.cc

Lines changed: 10 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
#include "absl/container/flat_hash_set.h"
2424
#include "absl/log/absl_check.h"
2525
#include "absl/status/status.h"
26+
#include "absl/status/statusor.h"
2627
#include "absl/strings/str_cat.h"
2728
#include "absl/strings/string_view.h"
29+
#include "common/internal/signature.h"
2830
#include "common/type.h"
2931
#include "common/type_kind.h"
3032

@@ -104,181 +106,6 @@ bool SignaturesOverlap(const OverloadDecl& lhs, const OverloadDecl& rhs) {
104106
return args_overlap;
105107
}
106108

107-
void AppendEscaped(std::string* result, absl::string_view str,
108-
bool escape_dot) {
109-
for (char c : str) {
110-
switch (c) {
111-
case '\\':
112-
case '(':
113-
case ')':
114-
case '<':
115-
case '>':
116-
case '"':
117-
case ',':
118-
result->push_back('\\');
119-
result->push_back(c);
120-
break;
121-
case '.':
122-
if (escape_dot) {
123-
result->push_back('\\');
124-
}
125-
result->push_back(c);
126-
break;
127-
default:
128-
result->push_back(c);
129-
break;
130-
}
131-
}
132-
}
133-
134-
void AppendTypeParameters(std::string* result, const Type& type);
135-
136-
// Recursively appends a string representation of the given `type` to `result`.
137-
// Type parameters are enclosed in angle brackets and separated by commas.
138-
void AppendTypeToOverloadId(std::string* result, const Type& type) {
139-
switch (type.kind()) {
140-
case TypeKind::kNull:
141-
absl::StrAppend(result, "null");
142-
return;
143-
case TypeKind::kBool:
144-
absl::StrAppend(result, "bool");
145-
return;
146-
case TypeKind::kInt:
147-
absl::StrAppend(result, "int");
148-
return;
149-
case TypeKind::kUint:
150-
absl::StrAppend(result, "uint");
151-
return;
152-
case TypeKind::kDouble:
153-
absl::StrAppend(result, "double");
154-
return;
155-
case TypeKind::kString:
156-
absl::StrAppend(result, "string");
157-
return;
158-
case TypeKind::kBytes:
159-
absl::StrAppend(result, "bytes");
160-
return;
161-
case TypeKind::kDuration:
162-
absl::StrAppend(result, "duration");
163-
return;
164-
case TypeKind::kTimestamp:
165-
absl::StrAppend(result, "timestamp");
166-
return;
167-
case TypeKind::kUnknown:
168-
absl::StrAppend(result, "unknown");
169-
return;
170-
case TypeKind::kError:
171-
absl::StrAppend(result, "error");
172-
return;
173-
case TypeKind::kAny:
174-
absl::StrAppend(result, "any");
175-
return;
176-
case TypeKind::kDyn:
177-
absl::StrAppend(result, "dyn");
178-
return;
179-
case TypeKind::kBoolWrapper:
180-
absl::StrAppend(result, "bool_wrapper");
181-
return;
182-
case TypeKind::kIntWrapper:
183-
absl::StrAppend(result, "int_wrapper");
184-
return;
185-
case TypeKind::kUintWrapper:
186-
absl::StrAppend(result, "uint_wrapper");
187-
return;
188-
case TypeKind::kDoubleWrapper:
189-
absl::StrAppend(result, "double_wrapper");
190-
return;
191-
case TypeKind::kStringWrapper:
192-
absl::StrAppend(result, "string_wrapper");
193-
return;
194-
case TypeKind::kBytesWrapper:
195-
absl::StrAppend(result, "bytes_wrapper");
196-
return;
197-
case TypeKind::kList:
198-
absl::StrAppend(result, "list");
199-
AppendTypeParameters(result, type);
200-
return;
201-
case TypeKind::kMap:
202-
absl::StrAppend(result, "map");
203-
AppendTypeParameters(result, type);
204-
return;
205-
case TypeKind::kFunction:
206-
absl::StrAppend(result, "function");
207-
AppendTypeParameters(result, type);
208-
return;
209-
case TypeKind::kEnum:
210-
absl::StrAppend(result, "enum");
211-
AppendTypeParameters(result, type);
212-
return;
213-
case TypeKind::kType:
214-
absl::StrAppend(result, "type");
215-
AppendTypeParameters(result, type);
216-
return;
217-
case TypeKind::kOpaque:
218-
result->push_back('"');
219-
AppendEscaped(result, type.name(), /*escape_dot=*/false);
220-
result->push_back('"');
221-
AppendTypeParameters(result, type);
222-
return;
223-
default: // This includes TypeKind::kStruct aka TypeKind::kTypeMessage
224-
AppendEscaped(result, type.name(), /*escape_dot=*/false);
225-
return;
226-
}
227-
}
228-
229-
void AppendTypeParameters(std::string* result, const Type& type) {
230-
const auto& parameters = type.GetParameters();
231-
if (!parameters.empty()) {
232-
result->push_back('<');
233-
for (size_t i = 0; i < parameters.size(); ++i) {
234-
AppendTypeToOverloadId(result, parameters[i]);
235-
if (i < parameters.size() - 1) {
236-
result->push_back(',');
237-
}
238-
}
239-
result->push_back('>');
240-
}
241-
}
242-
243-
// Generates an identifier for the overload based on the function name and
244-
// the types of the arguments. If `member` is true, the first argument type
245-
// is used as the receiver and is prepended to the function name, followed by
246-
// a dot.
247-
//
248-
// Examples:
249-
//
250-
// - `foo()`
251-
// - `foo(int)`
252-
// - `bar.foo(int)`
253-
// - `foo(int,string)`
254-
// - `foo(list<int>,list<string>)`
255-
// - `bar.foo(list<int>,list<"my_type"<A>>)`
256-
//
257-
std::string GenerateOverloadId(std::string_view function_name,
258-
const std::vector<Type>& args, bool member) {
259-
std::string result;
260-
if (member) {
261-
if (!args.empty()) {
262-
AppendTypeToOverloadId(&result, args[0]);
263-
} else {
264-
// This should never happen: a member function with no receiver.
265-
absl::StrAppend(&result, "error");
266-
}
267-
result.push_back('.');
268-
}
269-
AppendEscaped(&result, function_name, /*escape_dot=*/true);
270-
result.push_back('(');
271-
for (size_t i = member ? 1 : 0; i < args.size(); ++i) {
272-
AppendTypeToOverloadId(&result, args[i]);
273-
if (i < args.size() - 1) {
274-
result.push_back(',');
275-
}
276-
}
277-
result.push_back(')');
278-
279-
return result;
280-
}
281-
282109
template <typename Overload>
283110
void AddOverloadInternal(std::string_view function_name,
284111
std::vector<OverloadDecl>& insertion_order,
@@ -290,8 +117,14 @@ void AddOverloadInternal(std::string_view function_name,
290117

291118
if (overload.id().empty()) {
292119
OverloadDecl overload_decl = overload;
293-
overload_decl.set_id(GenerateOverloadId(function_name, overload_decl.args(),
294-
overload_decl.member()));
120+
absl::StatusOr<std::string> overload_id =
121+
common_internal::MakeOverloadSignature(
122+
function_name, overload_decl.args(), overload_decl.member());
123+
if (!overload_id.ok()) {
124+
status = overload_id.status();
125+
return;
126+
}
127+
overload_decl.set_id(*overload_id);
295128
AddOverloadInternal(function_name, insertion_order, overloads,
296129
std::move(overload_decl), status);
297130
return;

common/decl_test.cc

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414

1515
#include "common/decl.h"
1616

17-
#include "absl/log/die_if_null.h"
17+
#include <string>
18+
#include <vector>
19+
20+
#include "absl/log/die_if_null.h" // IWYU pragma: keep
1821
#include "absl/status/status.h"
1922
#include "common/constant.h"
2023
#include "common/type.h"
@@ -186,7 +189,6 @@ TEST(FunctionDecl, OverloadId) {
186189
MakeOverloadDecl(IntType{}, TimestampType{}),
187190
MakeOverloadDecl(IntType{}, IntWrapperType{}),
188191
MakeOverloadDecl(IntType{}, MessageType(descriptor)),
189-
MakeMemberOverloadDecl(IntType{}),
190192
MakeMemberOverloadDecl(StringType{}, StringType{}),
191193
MakeMemberOverloadDecl(StringType{}, StringType{},
192194
ListType(&arena, BoolType{})),
@@ -198,36 +200,20 @@ TEST(FunctionDecl, OverloadId) {
198200
ElementsAre(Property(&OverloadDecl::id, "hello()"),
199201
Property(&OverloadDecl::id, "hello(string)"),
200202
Property(&OverloadDecl::id, "hello(int,uint)"),
201-
Property(&OverloadDecl::id, "hello(list<A>)"),
202-
Property(&OverloadDecl::id, "hello(map<B,C>)"),
203-
Property(&OverloadDecl::id, "hello(\"bar\"<function<D>>)"),
203+
Property(&OverloadDecl::id, "hello(list<~A>)"),
204+
Property(&OverloadDecl::id, "hello(map<~B,~C>)"),
205+
Property(&OverloadDecl::id, "hello(bar<function<~D>>)"),
204206
Property(&OverloadDecl::id, "hello(any)"),
205207
Property(&OverloadDecl::id, "hello(duration)"),
206208
Property(&OverloadDecl::id, "hello(timestamp)"),
207209
Property(&OverloadDecl::id, "hello(int_wrapper)"),
208210
Property(&OverloadDecl::id,
209211
"hello(cel.expr.conformance.proto3.TestAllTypes)"),
210-
Property(&OverloadDecl::id, "error.hello()"),
211212
Property(&OverloadDecl::id, "string.hello()"),
212213
Property(&OverloadDecl::id, "string.hello(list<bool>)"),
213214
Property(&OverloadDecl::id, "string.hello(bool,dyn)")));
214215
}
215216

216-
TEST(FunctionDecl, OverloadIdEscaping) {
217-
google::protobuf::Arena arena;
218-
ASSERT_OK_AND_ASSIGN(
219-
auto function_decl,
220-
MakeFunctionDecl("h.(e),l<l>\\o",
221-
MakeMemberOverloadDecl(
222-
StringType{}, StringType{},
223-
ListType(&arena, TypeParamType("a,b.<C>.(d)\\e")))));
224-
225-
EXPECT_THAT(function_decl.overloads(),
226-
ElementsAre(Property(&OverloadDecl::id,
227-
"string.h\\.\\(e\\)\\,l\\<l\\>\\\\o(list<"
228-
"a\\,b.\\<C\\>.\\(d\\)\\\\e>)")));
229-
}
230-
231217
using common_internal::TypeIsAssignable;
232218

233219
TEST(TypeIsAssignable, BoolWrapper) {

common/internal/BUILD

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,34 @@ cc_library(
137137
"@com_google_protobuf//src/google/protobuf/io",
138138
],
139139
)
140+
141+
cc_library(
142+
name = "signature",
143+
srcs = ["signature.cc"],
144+
hdrs = ["signature.h"],
145+
deps = [
146+
"//common:type",
147+
"//common:type_kind",
148+
"//internal:status_macros",
149+
"@com_google_absl//absl/status",
150+
"@com_google_absl//absl/status:statusor",
151+
"@com_google_absl//absl/strings",
152+
"@com_google_absl//absl/strings:str_format",
153+
"@com_google_absl//absl/strings:string_view",
154+
],
155+
)
156+
157+
cc_test(
158+
name = "signature_test",
159+
srcs = ["signature_test.cc"],
160+
deps = [
161+
":signature",
162+
"//common:type",
163+
"//internal:testing",
164+
"//internal:testing_descriptor_pool",
165+
"@com_google_absl//absl/base:no_destructor",
166+
"@com_google_absl//absl/status",
167+
"@com_google_absl//absl/status:statusor",
168+
"@com_google_protobuf//:protobuf",
169+
],
170+
)

0 commit comments

Comments
 (0)