Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions scripts/cxx-api/parser/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,22 +193,20 @@ def build_snapshots(
failed_views = ", ".join(name for name, _ in errors)
raise RuntimeError(f"Failed to generate snapshots: {failed_views}")
else:
with tempfile.TemporaryDirectory(prefix="cxx-api-test-") as work_dir:
snapshot = build_snapshot_for_view(
api_view="Test",
react_native_dir=react_native_dir,
include_directories=[],
exclude_patterns=[],
definitions={},
output_dir=output_dir,
codegen_platform=None,
verbose=verbose,
input_filter=input_filter,
work_dir=work_dir,
)

if verbose:
print(snapshot)
snapshot = build_snapshot_for_view(
api_view="Test",
react_native_dir=react_native_dir,
include_directories=[],
exclude_patterns=[],
definitions={},
output_dir=output_dir,
codegen_platform=None,
verbose=verbose,
input_filter=input_filter,
)

if verbose:
print(snapshot)


def get_default_snapshot_dir() -> str:
Expand Down
52 changes: 51 additions & 1 deletion scripts/cxx-api/parser/builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@
resolve_linked_text_name,
split_specialization,
)
from .utils.argument_parsing import _find_matching_angle, _split_arguments
from .utils.argument_parsing import (
_find_matching_angle,
_split_arguments,
format_parsed_type,
parse_type_with_argstrings,
)


@dataclass
Expand Down Expand Up @@ -161,8 +166,14 @@ def get_base_classes(
) -> list:
"""
Get the base classes of a compound object.

Deduplicates base classes by name. Doxygen can emit duplicate
``basecompoundref`` entries when a class inherits constructors via
``using Base::Base;`` — the using-declaration is incorrectly reported
as an additional base class reference.
"""
base_classes = []
seen_names: set[str] = set()
if compound_object.basecompoundref:
for base in compound_object.basecompoundref:
# base is a compoundRefType with:
Expand All @@ -179,6 +190,10 @@ def get_base_classes(
# Ignore private base classes
continue

if base_name in seen_names:
continue
seen_names.add(base_name)

base_classes.append(
base_class(
base_name,
Expand Down Expand Up @@ -307,6 +322,16 @@ def get_doxygen_params(
if param.get_type()
else ""
)

# Doxygen may incorrectly cross-reference parameter names inside
# inline function pointer types to member variables of the enclosing
# class, producing qualified paths like "const void*
# ns::Class::data" instead of "const void* data". Re-parse the
# type through parse_type_with_argstrings which delegates to
# _parse_single_argument — that already strips "::" from names.
segments = parse_type_with_argstrings(param_type)
if len(segments) > 1:
param_type = format_parsed_type(segments)
param_name = param.declname or param.defname or None
param_default = (
resolve_linked_text_name(param.defval)[0].strip() if param.defval else None
Expand All @@ -333,6 +358,8 @@ def get_doxygen_params(
+ param_array
)
param_name = None
elif param_name:
param_name += param_array
else:
param_type += param_array

Expand All @@ -350,6 +377,29 @@ def get_doxygen_params(
param_type[:insert_pos] + param_name + param_type[insert_pos:]
)
param_name = None
else:
# Doxygen bug: for pointer-to-member-function params with
# ref-qualifiers (& or &&), Doxygen incorrectly embeds the
# parameter name in the type string between cv-qualifiers
# and the ref-qualifier, and omits <declname> entirely:
# <type>R(ns::*)() const asFoo &amp;</type>
# Detect this pattern and reconstruct the correct type:
# R(ns::*asFoo)() const &
m = re.search(
r"(\([^)]*::\*\))" # group 1: ptr-to-member declarator
r"(.+?)" # group 2: param list + cv-qualifiers
r"\s+([a-zA-Z_]\w*)" # group 3: misplaced identifier
r"\s*(&{1,2})\s*$", # group 4: ref-qualifier
param_type,
)
if m:
param_type = (
param_type[: m.end(1) - 1] # up to ')' of (ns::*)
+ m.group(3) # insert extracted name
+ param_type[m.end(1) - 1 : m.end(2)] # ')' + params + cv-quals
+ " "
+ m.group(4) # ref-qualifier
)

qualifiers, core_type = extract_qualifiers(param_type)
arguments.append((qualifiers, core_type, param_name, param_default))
Expand Down
2 changes: 2 additions & 0 deletions scripts/cxx-api/parser/member/variable_member.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ def to_string(
result += f"{qualified_type} (*{name})({formatted_args})"
else:
result += f"{format_parsed_type(self._parsed_type)} {name}"
if self.argstring:
result += self.argstring

if STORE_INITIALIZERS_IN_SNAPSHOT and self.value is not None:
if self.is_brace_initializer:
Expand Down
5 changes: 5 additions & 0 deletions scripts/cxx-api/parser/scope/base_scope_kind.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ def _format_scope_body(self, scope: Scope, member_suffix: str = "") -> str:
stringified_members = [
member.to_string(2) + member_suffix for member in scope.get_members()
]

stringified_members = natsorted(stringified_members)
# Deduplicate members that produce identical signatures (e.g.
# constructors inherited from multiple bases).
stringified_members = list(dict.fromkeys(stringified_members))

result = "{"
if stringified_members:
result += "\n" + "\n".join(stringified_members)
Expand Down
2 changes: 2 additions & 0 deletions scripts/cxx-api/parser/scope/namespace_scope_kind.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ def to_string(self, scope: Scope) -> str:
result = []
for kind in MemberKind:
sorted_group = natsorted(groups[kind])
# Deduplicate members with identical signatures.
sorted_group = list(dict.fromkeys(sorted_group))
result.extend(sorted_group)

return "\n".join(result)
8 changes: 8 additions & 0 deletions scripts/cxx-api/parser/utils/argument_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,14 @@ def parse_type_with_argstrings(
i = close + 1
continue

# Complex declarator starting with * or &, e.g. *(*fp)(int)
# in "int(*(*fp)(int))(double)". Argument lists never start
# with pointer/reference characters.
if stripped and stripped[0] in ("*", "&"):
current_text.append(type_str[i : close + 1])
i = close + 1
continue

# Try to parse as a function argument list
args: list[Argument] = []
if stripped:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
struct test::Converter<int> : public test::ConverterBase<int> {
public void doSomething();
}

template <typename T>
struct test::Converter {
}

template <typename T>
struct test::ConverterBase {
public ConverterBase() = default;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

namespace test {

template <typename T>
struct ConverterBase {
ConverterBase() = default;
};

template <typename T>
struct Converter {};

template <>
struct Converter<int> : public ConverterBase<int> {
using ConverterBase<int>::ConverterBase;
void doSomething();
};

} // namespace test
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
void test::arrayParam(const char name[]);
void test::arrayParamSized(int values[10]);
void test::arrayParamUnnamed(const char[]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

namespace test {

void arrayParam(const char name[]);
void arrayParamSized(int values[10]);
void arrayParamUnnamed(const char[]);

} // namespace test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const char test::ViewComponentName[];
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

namespace test {

const char ViewComponentName[] = "View";

} // namespace test
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class test::BaseTextShadowNode : public test::ShadowNode {
public BaseTextShadowNode(const test::ShadowNode& source, const test::ShadowNode::Fragment& fragment);
public BaseTextShadowNode(const test::ShadowNode::Fragment& fragment, const test::ShadowNode::Shared& family, test::ShadowNode::Traits traits);
}

class test::ConcreteViewShadowNode : public test::ShadowNode {
public ConcreteViewShadowNode(const test::ShadowNode& source, const test::ShadowNode::Fragment& fragment);
public ConcreteViewShadowNode(const test::ShadowNode::Fragment& fragment, const test::ShadowNode::Shared& family, test::ShadowNode::Traits traits);
}

class test::ParagraphShadowNode : public test::ConcreteViewShadowNode, public test::BaseTextShadowNode {
public ParagraphShadowNode(const test::ShadowNode& source, const test::ShadowNode::Fragment& fragment);
public ParagraphShadowNode(const test::ShadowNode::Fragment& fragment, const test::ShadowNode::Shared& family, test::ShadowNode::Traits traits);
}

class test::ShadowNode {
}

enum test::ShadowNode::Traits {
None,
}

struct test::ShadowNode::Fragment {
}

struct test::ShadowNode::Shared {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

namespace test {

class ShadowNode {
public:
struct Fragment {};
struct Shared {};
enum class Traits { None };
};

class ConcreteViewShadowNode : public ShadowNode {
public:
ConcreteViewShadowNode(const ShadowNode &source, const Fragment &fragment);
ConcreteViewShadowNode(const Fragment &fragment, const Shared &family, Traits traits);
};

class BaseTextShadowNode : public ShadowNode {
public:
BaseTextShadowNode(const ShadowNode &source, const Fragment &fragment);
BaseTextShadowNode(const Fragment &fragment, const Shared &family, Traits traits);
};

class ParagraphShadowNode : public ConcreteViewShadowNode, public BaseTextShadowNode {
public:
using BaseTextShadowNode::BaseTextShadowNode;
using ConcreteViewShadowNode::ConcreteViewShadowNode;
};

} // namespace test
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
struct folly::dynamic {
}


template <typename R, typename... T>
R test::jsArg(const folly::dynamic& arg, R(folly::dynamic::*asFoo)() const &, const T &... desc);
template <typename R, typename... T>
R test::jsArg(const folly::dynamic& arg, R(folly::dynamic::*asFoo)() const, const T &... desc);
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

namespace folly {

struct dynamic {};

} // namespace folly

namespace test {

template <typename R, typename... T>
R jsArg(const folly::dynamic &arg, R (folly::dynamic::*asFoo)() const, const T &...desc);
template <typename R, typename... T>
R jsArg(const folly::dynamic &arg, R (folly::dynamic::*asFoo)() const &, const T &...desc);

} // namespace test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class test::Runtime {
public int data;
public virtual void getStringData(void* ctx, void(*)(void* ctx, bool ascii, const void* data, size_t num) cb);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#pragma once

namespace test {

class Runtime {
public:
int data;
virtual void getStringData(
void* ctx,
void (*cb)(void* ctx, bool ascii, const void* data, size_t num));
};

} // namespace test
Loading