srctree

Robin Linden parent 8fbe5ecc cbf9ffcb
meta: Enable clang-tidy's misc-no-recursion lint

Most of these places need some form of recursion depth restriction or rewriting.
.clang-tidy added: 60, removed: 22, total 38
@@ -16,8 +16,6 @@
#
# -misc-const-correctness: Consts some things that can't be const, and very very noisy.
#
# -misc-no-recursion: We use a lot of recursion.
#
# -modernize-make-unique, -modernize-use-emplace: Clang doesn't implement p0960
# yet, and we're not adding c-tors to all our structs.
#
@@ -75,7 +73,6 @@ Checks: >
-cppcoreguidelines-special-member-functions,
-google-build-using-namespace,
-misc-const-correctness,
-misc-no-recursion,
-modernize-make-unique,
-modernize-use-emplace,
-modernize-use-nodiscard,
 
css/parser.cpp added: 60, removed: 22, total 38
@@ -405,6 +405,7 @@ constexpr void Parser::skip_whitespace() {
}
}
 
// NOLINTNEXTLINE(misc-no-recursion)
void Parser::skip_whitespace_and_comments() {
if (starts_with("/*")) {
advance(2);
@@ -419,6 +420,7 @@ void Parser::skip_whitespace_and_comments() {
}
}
 
// NOLINTNEXTLINE(misc-no-recursion)
std::optional<css::Rule> Parser::parse_rule() {
Rule rule{};
while (peek() != '{') {
 
dom/dom.cpp added: 60, removed: 22, total 38
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2021-2023 Robin Lindén <dev@robinlinden.eu>
// SPDX-FileCopyrightText: 2021-2024 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
@@ -14,6 +14,7 @@
namespace dom {
namespace {
 
// NOLINTNEXTLINE(misc-no-recursion)
void print_node(dom::Node const &node, std::ostream &os, std::uint8_t depth = 0) {
for (std::uint8_t i = 0; i < depth; ++i) {
os << " ";
 
html2/parser_states.cpp added: 60, removed: 22, total 38
@@ -301,6 +301,7 @@ std::optional<InsertionMode> BeforeHead::process(IActions &a, html2::Token const
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inhead
// Incomplete.
// TODO(robinlinden): Template nonsense.
// NOLINTNEXTLINE(misc-no-recursion)
std::optional<InsertionMode> InHead::process(IActions &a, html2::Token const &token) {
if (is_boring_whitespace(token)) {
// TODO(robinlinden): Should be inserting characters, but our last
@@ -420,6 +421,7 @@ std::optional<InsertionMode> InHeadNoscript::process(IActions &a, html2::Token c
}
 
// https://html.spec.whatwg.org/multipage/parsing.html#the-after-head-insertion-mode
// NOLINTNEXTLINE(misc-no-recursion)
std::optional<InsertionMode> AfterHead::process(IActions &a, html2::Token const &token) {
if (is_boring_whitespace(token)) {
a.insert_character(std::get<html2::CharacterToken>(token));
@@ -500,6 +502,7 @@ std::optional<InsertionMode> AfterHead::process(IActions &a, html2::Token const
 
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody
// Incomplete.
// NOLINTNEXTLINE(misc-no-recursion)
std::optional<InsertionMode> InBody::process(IActions &a, html2::Token const &token) {
auto const *character = std::get_if<html2::CharacterToken>(&token);
if (character != nullptr && character->data == '\0') {
 
layout/layout.cpp added: 60, removed: 22, total 38
@@ -70,6 +70,7 @@ bool last_node_was_anonymous(LayoutBox const &box) {
}
 
// https://www.w3.org/TR/CSS2/visuren.html#box-gen
// NOLINTNEXTLINE(misc-no-recursion)
std::optional<LayoutBox> create_tree(style::StyledNode const &node) {
if (auto const *text = std::get_if<dom::Text>(&node.node)) {
return LayoutBox{.node = &node, .layout_text = std::string_view{text->text}};
@@ -115,6 +116,7 @@ constexpr bool is_non_space_whitespace(char c) {
return c != ' ' && util::is_whitespace(c);
}
 
// NOLINTNEXTLINE(misc-no-recursion)
void remove_empty_text_boxes(LayoutBox &box) {
for (auto it = box.children.begin(); it != box.children.end();) {
auto text = it->text();
@@ -218,6 +220,7 @@ void collapse_whitespace(LayoutBox &box) {
remove_empty_text_boxes(box);
}
 
// NOLINTNEXTLINE(misc-no-recursion)
void apply_text_transforms(LayoutBox &box) {
if (std::holds_alternative<std::string>(box.layout_text)
|| std::holds_alternative<std::string_view>(box.layout_text)) {
@@ -270,6 +273,7 @@ void calculate_position(LayoutBox &box, geom::Rect const &parent) {
box.dimensions.content.y = parent.y + parent.height + d.border.top + d.padding.top + d.margin.top;
}
 
// NOLINTNEXTLINE(misc-no-recursion)
void Layouter::layout(LayoutBox &box, geom::Rect const &bounds) const {
if (box.is_anonymous_block()) {
layout_anonymous_block(box, bounds);
@@ -295,6 +299,7 @@ type::Weight to_type(std::optional<style::FontWeight> const &weight) {
return type::Weight::Bold;
}
 
// NOLINTNEXTLINE(misc-no-recursion)
void Layouter::layout_inline(LayoutBox &box, geom::Rect const &bounds) const {
assert(box.node);
auto font_size = box.get_property<css::PropertyId::FontSize>();
@@ -329,6 +334,7 @@ void Layouter::layout_inline(LayoutBox &box, geom::Rect const &bounds) const {
calculate_height(box, font_size);
}
 
// NOLINTNEXTLINE(misc-no-recursion)
void Layouter::layout_block(LayoutBox &box, geom::Rect const &bounds) const {
assert(box.node);
auto font_size = box.get_property<css::PropertyId::FontSize>();
@@ -343,6 +349,7 @@ void Layouter::layout_block(LayoutBox &box, geom::Rect const &bounds) const {
calculate_height(box, font_size);
}
 
// NOLINTNEXTLINE(misc-no-recursion)
void Layouter::layout_anonymous_block(LayoutBox &box, geom::Rect const &bounds) const {
calculate_position(box, bounds);
int last_child_end{};
 
layout/layout_box.cpp added: 60, removed: 22, total 38
@@ -52,6 +52,7 @@ std::string to_str(geom::EdgeSize const &edge) {
return std::move(ss).str();
}
 
// NOLINTNEXTLINE(misc-no-recursion)
void print_box(LayoutBox const &box, std::ostream &os, std::uint8_t depth = 0) {
for (std::uint8_t i = 0; i < depth; ++i) {
os << " ";
@@ -89,6 +90,7 @@ std::optional<std::string_view> LayoutBox::text() const {
return std::visit(Visitor{}, layout_text);
}
 
// NOLINTNEXTLINE(misc-no-recursion)
LayoutBox const *box_at_position(LayoutBox const &box, geom::Position p) {
if (!box.dimensions.contains(p)) {
return nullptr;
 
layout/layout_box.h added: 60, removed: 22, total 38
@@ -21,11 +21,13 @@
 
namespace layout {
 
// NOLINTNEXTLINE(misc-no-recursion)
struct LayoutBox {
style::StyledNode const *node;
BoxModel dimensions;
std::vector<LayoutBox> children;
std::variant<std::monostate, std::string_view, std::string> layout_text;
// NOLINTNEXTLINE(misc-no-recursion)
[[nodiscard]] bool operator==(LayoutBox const &) const = default;
 
bool is_anonymous_block() const { return node == nullptr; }
 
layout/layout_box_test.cpp added: 60, removed: 22, total 38
@@ -25,6 +25,7 @@ namespace {
 
// Until we have a nicer tree-creation abstraction for the tests, this needs to
// be called if a test relies on property inheritance.
// NOLINTNEXTLINE(misc-no-recursion)
void set_up_parent_ptrs(style::StyledNode &parent) {
for (auto &child : parent.children) {
child.parent = &parent;
 
layout/layout_test.cpp added: 60, removed: 22, total 38
@@ -38,6 +38,7 @@ public:
 
// Until we have a nicer tree-creation abstraction for the tests, this needs to
// be called if a test relies on property inheritance.
// NOLINTNEXTLINE(misc-no-recursion)
void set_up_parent_ptrs(style::StyledNode &parent) {
for (auto &child : parent.children) {
child.parent = &parent;
 
render/render.cpp added: 60, removed: 22, total 38
@@ -127,6 +127,7 @@ bool should_render(layout::LayoutBox const &layout) {
return layout.get_property<css::PropertyId::Display>().has_value();
}
 
// NOLINTNEXTLINE(misc-no-recursion)
void render_layout_impl(gfx::ICanvas &painter, layout::LayoutBox const &layout, std::optional<geom::Rect> const &clip) {
if (clip && clip->intersected(layout.dimensions.border_box()).empty()) {
return;
@@ -170,6 +171,7 @@ void render_layout(gfx::ICanvas &painter, layout::LayoutBox const &layout, std::
namespace debug {
namespace {
 
// NOLINTNEXTLINE(misc-no-recursion)
void render_layout_depth_impl(gfx::ICanvas &painter, layout::LayoutBox const &layout) {
painter.fill_rect(layout.dimensions.padding_box(), {0xFF, 0xFF, 0xFF, 0x30});
for (auto const &child : layout.children) {
 
style/style.cpp added: 60, removed: 22, total 38
@@ -40,6 +40,7 @@ bool has_class(dom::Element const &element, std::string_view needle_class) {
} // namespace
 
// TODO(robinlinden): This needs to match more things.
// NOLINTNEXTLINE(misc-no-recursion)
bool is_match(style::StyledNode const &node, std::string_view selector) {
auto const &element = std::get<dom::Element>(node.node);
// https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes
@@ -205,6 +206,7 @@ MatchingProperties matching_properties(
}
 
namespace {
// NOLINTNEXTLINE(misc-no-recursion)
void style_tree_impl(StyledNode &current,
dom::Node const &root,
css::StyleSheet const &stylesheet,
 
style/styled_node.cpp added: 60, removed: 22, total 38
@@ -175,6 +175,7 @@ gfx::Color parse_color(std::string_view str) {
return gfx::Color{0xFF, 0, 0};
}
 
// NOLINTNEXTLINE(misc-no-recursion)
std::string_view get_parent_raw_property(style::StyledNode const &node, css::PropertyId property) {
if (node.parent != nullptr) {
return node.parent->get_raw_property(property);
@@ -216,6 +217,7 @@ int UnresolvedBorderWidth::resolve(int font_size, int root_font_size, std::optio
return width.resolve(font_size, root_font_size, percent_relative_to);
}
 
// NOLINTNEXTLINE(misc-no-recursion)
std::string_view StyledNode::get_raw_property(css::PropertyId property) const {
// We don't support selector specificity yet, so the last property is found
// in order to allow website style to override the browser built-in style.
@@ -285,6 +287,7 @@ std::string_view StyledNode::get_raw_property(css::PropertyId property) const {
return it->second;
}
 
// NOLINTNEXTLINE(misc-no-recursion)
std::optional<std::string_view> StyledNode::resolve_variable(std::string_view name) const {
auto prop = std::ranges::find(custom_properties, name, &std::pair<std::string, std::string>::first);
if (prop == end(custom_properties)) {
@@ -515,6 +518,7 @@ constexpr auto kFontSizeAbsoluteSizeKeywords = std::to_array<std::pair<std::stri
{"xxx-large", 3 / 1.f},
});
 
// NOLINTNEXTLINE(misc-no-recursion)
int StyledNode::get_font_size_property() const {
auto get_closest_font_size_and_owner =
[](StyledNode const *starting_node) -> std::optional<std::pair<std::string_view, StyledNode const *>> {
@@ -543,6 +547,7 @@ int StyledNode::get_font_size_property() const {
return std::lround(it->second * kMediumFontSize);
}
 
// NOLINTNEXTLINE(misc-no-recursion)
auto parent_or_default_font_size = [&] {
auto const *owner = closest->second;
if (owner->parent == nullptr) {
@@ -617,6 +622,7 @@ int StyledNode::get_font_size_property() const {
}
 
// https://drafts.csswg.org/css-fonts-4/#font-weight-prop
// NOLINTNEXTLINE(misc-no-recursion)
std::optional<FontWeight> StyledNode::get_font_weight_property() const {
auto raw = get_raw_property(css::PropertyId::FontWeight);
if (raw == "normal") {
@@ -628,6 +634,7 @@ std::optional<FontWeight> StyledNode::get_font_weight_property() const {
}
 
if (raw == "bolder") {
// NOLINTNEXTLINE(misc-no-recursion)
auto parent_weight = [&] {
if (parent == nullptr) {
return FontWeight::normal();
@@ -653,6 +660,7 @@ std::optional<FontWeight> StyledNode::get_font_weight_property() const {
}
 
if (raw == "lighter") {
// NOLINTNEXTLINE(misc-no-recursion)
auto parent_weight = [&] {
if (parent == nullptr) {
return FontWeight::normal();
 
style/styled_node.h added: 60, removed: 22, total 38
@@ -111,6 +111,7 @@ struct UnresolvedBorderWidth {
int resolve(int font_size, int root_font_size, std::optional<int> percent_relative_to = std::nullopt) const;
};
 
// NOLINTNEXTLINE(misc-no-recursion)
struct StyledNode {
dom::Node const &node;
std::vector<std::pair<css::PropertyId, std::string>> properties;
@@ -191,10 +192,12 @@ private:
std::pair<int, int> get_border_radius_property(css::PropertyId) const;
};
 
// NOLINTBEGIN(misc-no-recursion)
[[nodiscard]] inline bool operator==(style::StyledNode const &a, style::StyledNode const &b) noexcept {
return a.node == b.node && a.properties == b.properties && a.custom_properties == b.custom_properties
&& a.children == b.children;
}
// NOLINTEND(misc-no-recursion)
 
inline std::string_view dom_name(StyledNode const &node) {
return std::get<dom::Element>(node.node).name;
 
tui/tui.cpp added: 60, removed: 22, total 38
@@ -20,6 +20,7 @@ namespace {
 
ftxui::Element element_from_node(layout::LayoutBox const &box);
 
// NOLINTNEXTLINE(misc-no-recursion)
ftxui::Elements parse_children(layout::LayoutBox const &box) {
ftxui::Elements children;
for (auto const &child : box.children) {
@@ -29,6 +30,7 @@ ftxui::Elements parse_children(layout::LayoutBox const &box) {
return children;
}
 
// NOLINTNEXTLINE(misc-no-recursion)
ftxui::Element element_from_node(layout::LayoutBox const &box) {
if (box.is_anonymous_block()) {
return flex(vbox(parse_children(box)));
 
unicode/normalization.cpp added: 60, removed: 22, total 38
@@ -18,6 +18,7 @@
namespace unicode {
namespace {
 
// NOLINTNEXTLINE(misc-no-recursion)
void decompose_to(std::ostream &os, char32_t code_point) {
// * clang-tidy thinks std::ranges::lower_bound is provided by
// <bits/ranges_algo.h> when it's actually provided by <algorithm>.
 
uri/uri.cpp added: 60, removed: 22, total 38
@@ -32,6 +32,7 @@ void normalize(Uri &uri) {
}
}
 
// NOLINTNEXTLINE(misc-no-recursion)
[[nodiscard]] bool complete_from_base_if_needed(Uri &uri, Uri const &base) {
if (uri.scheme.empty() && uri.authority.host.empty() && uri.path.starts_with('/')) {
// Origin-relative.
@@ -74,6 +75,7 @@ void normalize(Uri &uri) {
 
} // namespace
 
// NOLINTNEXTLINE(misc-no-recursion)
std::optional<Uri> Uri::parse(std::string uristr, std::optional<std::reference_wrapper<Uri const>> base_uri) {
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164
// Fuzz-testing w/ libstdc++13 still breaks the stack if 2048 characters are allowed.
 
url/url.cpp added: 60, removed: 22, total 38
@@ -281,6 +281,7 @@ std::string Url::serialize(bool exclude_fragment, bool rfc3986_norm) const {
}
 
// https://url.spec.whatwg.org/#concept-url-origin
// NOLINTNEXTLINE(misc-no-recursion)
Origin Url::origin() const {
// Return tuple origin of the path URL
if (scheme == "blob") {
 
wasm/byte_code_parser.cpp added: 60, removed: 22, total 38
@@ -661,6 +661,7 @@ tl::expected<Module, ModuleParseError> ByteCodeParser::parse_module(std::istream
return module;
}
 
// NOLINTNEXTLINE(misc-no-recursion)
std::optional<std::vector<instructions::Instruction>> ByteCodeParser::parse_instructions(std::istream &is) {
using namespace instructions;
std::vector<Instruction> instructions{};