Introduce FindIfOrNull() FindIfOrNone() and Contains() (#5322)

`FindIfOrNull` returns a pointer to the element in the range if it's
found, and nullptr otherwise. `FindIfOrNone` returns a copy of the
element in the range if it's found, and `T::None` (for a range of
elements of type `T`) otherwise. `Contains` returns a bool indicating
whether the element in the range is found.

These functions replace `llvm::find()` and `llvm::find_if()` when you
want a single answer back instead of an iterator. This avoids the need
to check against `end()`, allowing the return condition to be tested as
a standard bool.

We replace uses of `find()` and `find_if()` that did not require an
iterator with these new helpers.

Note that the return type of `FindIfOrNull` is a pointer since we can
not write `optional<T&>`, which must be tested for null. If the null
check is omitted, UB occurs and the resulting code may end up with an
incorrect pointer (https://crbug.com/40153300) into the range (or
elsewhere), rather than a null dereference. And this would be very
confusing to debug. Hopefully debug builds and sanitizers keep this from
being an issue we sink a bunch of time into debugging.
This commit is contained in:
Dana Jansens
2025-04-18 14:17:48 +00:00
committed by GitHub
parent 55705aaef8
commit 9a6c74f0cd
11 changed files with 207 additions and 17 deletions
+2 -1
View File
@@ -9,6 +9,7 @@
#include <utility>
#include "common/error.h"
#include "common/find.h"
#include "common/struct_reflection.h"
#include "toolchain/parse/tree.h"
#include "toolchain/parse/tree_and_subtrees.h"
@@ -210,7 +211,7 @@ auto NodeExtractor::MatchesNodeIdOneOf(
*trace_ << "\n";
}
return false;
} else if (llvm::find(kinds, node_kind) == kinds.end()) {
} else if (!Contains(kinds, node_kind)) {
if (trace_) {
*trace_ << "NodeIdOneOf error: wrong kind " << node_kind << ", expected ";
trace_kinds();