Merge pull request #2423 from hzeller/feature-20250531-limit-down-cast

Don't use down_cast<> with the assumption that type-mismatch returns …
diff --git a/verible/common/analysis/matcher/BUILD b/verible/common/analysis/matcher/BUILD
index d4a1715..2d93eb9 100644
--- a/verible/common/analysis/matcher/BUILD
+++ b/verible/common/analysis/matcher/BUILD
@@ -17,7 +17,7 @@
     hdrs = ["bound-symbol-manager.h"],
     deps = [
         "//verible/common/text:symbol",
-        "//verible/common/util:casts",
+        "//verible/common/text:tree-utils",
         "//verible/common/util:container-util",
         "//verible/common/util:logging",
     ],
diff --git a/verible/common/analysis/matcher/bound-symbol-manager.h b/verible/common/analysis/matcher/bound-symbol-manager.h
index 0feca14..46ef0e4 100644
--- a/verible/common/analysis/matcher/bound-symbol-manager.h
+++ b/verible/common/analysis/matcher/bound-symbol-manager.h
@@ -19,9 +19,11 @@
 #include <string>
 
 #include "verible/common/text/symbol.h"
-#include "verible/common/util/casts.h"
+#include "verible/common/text/tree-utils.h"
 
 namespace verible {
+class SyntaxTreeNode;
+class SyntaxTreeLeaf;
 namespace matcher {
 
 // Manages sets of Bound Symbols created when matching against a syntax tree.
@@ -52,9 +54,14 @@
     return bound_symbols_;
   }
 
-  template <typename T>
-  const T *GetAs(const std::string &key) const {
-    return down_cast<const T *>(FindSymbol(key));
+  // Return named node as Node if available of of that type.
+  const SyntaxTreeNode *GetAsNode(const std::string &key) const {
+    return verible::MaybeNode(FindSymbol(key));
+  }
+
+  // Return named node as Node if available of of that type.
+  const SyntaxTreeLeaf *GetAsLeaf(const std::string &key) const {
+    return verible::MaybeLeaf(FindSymbol(key));
   }
 
  private:
diff --git a/verible/common/text/symbol.h b/verible/common/text/symbol.h
index 4a349da..ad8e95f 100644
--- a/verible/common/text/symbol.h
+++ b/verible/common/text/symbol.h
@@ -55,8 +55,6 @@
 }
 constexpr SymbolTag LeafTag(int tag) { return {SymbolKind::kLeaf, tag}; }
 
-// forward declare Visitor classes to allow references in Symbol
-
 class Symbol {
  public:
   virtual ~Symbol() = default;
diff --git a/verible/common/text/tree-utils.cc b/verible/common/text/tree-utils.cc
index cadd313..b76be7b 100644
--- a/verible/common/text/tree-utils.cc
+++ b/verible/common/text/tree-utils.cc
@@ -126,6 +126,15 @@
   return down_cast<const SyntaxTreeLeaf &>(symbol);
 }
 
+const SyntaxTreeNode *MaybeNode(const Symbol *symbol) {
+  if (!symbol || symbol->Kind() != SymbolKind::kNode) return nullptr;
+  return static_cast<const SyntaxTreeNode *>(symbol);
+}
+const SyntaxTreeLeaf *MaybeLeaf(const Symbol *symbol) {
+  if (!symbol || symbol->Kind() != SymbolKind::kLeaf) return nullptr;
+  return static_cast<const SyntaxTreeLeaf *>(symbol);
+}
+
 namespace {
 // FirstSubtreeFinderMutable is a visitor class that supports the implementation
 // of FindFirstSubtreeMutable().  It is derived from
diff --git a/verible/common/text/tree-utils.h b/verible/common/text/tree-utils.h
index 8a18924..475295b 100644
--- a/verible/common/text/tree-utils.h
+++ b/verible/common/text/tree-utils.h
@@ -30,6 +30,9 @@
 #include "verible/common/util/logging.h"
 #include "verible/common/util/type-traits.h"
 
+// TODO: the functions below that can crash while asserting a type should
+// probably return a usable error (std::optional).
+
 namespace verible {
 
 // Returns the leftmost/rightmost leaf contained in Symbol.
@@ -47,6 +50,7 @@
 std::string_view StringSpanOfSymbol(const Symbol &lsym, const Symbol &rsym);
 
 // Returns a SyntaxTreeNode down_casted from a Symbol.
+// Will panic if not of that kind.
 const SyntaxTreeNode &SymbolCastToNode(const Symbol &);
 // Mutable variant.
 SyntaxTreeNode &SymbolCastToNode(Symbol &);  // NOLINT
@@ -59,8 +63,15 @@
 inline SyntaxTreeNode &SymbolCastToNode(SyntaxTreeNode &node) { return node; }
 
 // Returns a SyntaxTreeLeaf down_casted from a Symbol.
+// Will panic if not of that kind.
 const SyntaxTreeLeaf &SymbolCastToLeaf(const Symbol &);
 
+// Return Node if symbol is of that kind, otherwise nullptr.
+const SyntaxTreeNode *MaybeNode(const Symbol *symbol);
+
+// Return Leaf if symbol is of that kind, otherwise nullptr.
+const SyntaxTreeLeaf *MaybeLeaf(const Symbol *symbol);
+
 // Unwrap layers of only-child nodes until reaching a leaf or a node with
 // multiple children.
 const Symbol *DescendThroughSingletons(const Symbol &symbol);
diff --git a/verible/verilog/CST/BUILD b/verible/verilog/CST/BUILD
index a2ecea2..98f4c9b 100644
--- a/verible/verilog/CST/BUILD
+++ b/verible/verilog/CST/BUILD
@@ -98,6 +98,7 @@
         "//verible/common/text:concrete-syntax-tree",
         "//verible/common/text:symbol",
         "//verible/common/text:token-info",
+        "//verible/common/text:tree-utils",
         "//verible/common/util:logging",
         "@abseil-cpp//absl/strings",
     ],
diff --git a/verible/verilog/CST/expression.cc b/verible/verilog/CST/expression.cc
index 39d75de..7256626 100644
--- a/verible/verilog/CST/expression.cc
+++ b/verible/verilog/CST/expression.cc
@@ -104,8 +104,9 @@
     return nullptr;
   }
   const verible::Symbol *leaf_symbol = node->front().get();
-  return &verible::down_cast<const verible::SyntaxTreeLeaf *>(leaf_symbol)
-              ->get();
+  const verible::SyntaxTreeLeaf *leaf = verible::MaybeLeaf(leaf_symbol);
+  if (!leaf) return nullptr;
+  return &leaf->get();
 }
 
 const verible::Symbol *GetUnaryPrefixOperand(const verible::Symbol &symbol) {
diff --git a/verible/verilog/CST/identifier.cc b/verible/verilog/CST/identifier.cc
index e5adc82..9f03a0c 100644
--- a/verible/verilog/CST/identifier.cc
+++ b/verible/verilog/CST/identifier.cc
@@ -72,8 +72,7 @@
     return nullptr;
   }
   const auto &node = down_cast<const verible::SyntaxTreeNode &>(symbol);
-  const auto *leaf = down_cast<const verible::SyntaxTreeLeaf *>(node[0].get());
-  return leaf;
+  return verible::MaybeLeaf(node[0].get());
 }
 
 const verible::SyntaxTreeLeaf *AutoUnwrapIdentifier(
diff --git a/verible/verilog/CST/verilog-treebuilder-utils.cc b/verible/verilog/CST/verilog-treebuilder-utils.cc
index 00af7e6..91eea0f 100644
--- a/verible/verilog/CST/verilog-treebuilder-utils.cc
+++ b/verible/verilog/CST/verilog-treebuilder-utils.cc
@@ -22,12 +22,11 @@
 #include "verible/common/text/concrete-syntax-tree.h"
 #include "verible/common/text/symbol.h"
 #include "verible/common/text/token-info.h"
+#include "verible/common/text/tree-utils.h"
 #include "verible/common/util/logging.h"
 
 namespace verilog {
 
-using verible::down_cast;
-
 // Set of utility functions for embedded a statement into a certain context.
 std::string EmbedInClass(std::string_view text) {
   return absl::StrCat("class test_class;\n", text, "\nendclass\n");
@@ -47,7 +46,7 @@
 }
 
 void ExpectString(const verible::SymbolPtr &symbol, std::string_view expected) {
-  const auto *leaf = down_cast<const verible::SyntaxTreeLeaf *>(symbol.get());
+  const verible::SyntaxTreeLeaf *leaf = verible::MaybeLeaf(symbol.get());
   CHECK(leaf != nullptr) << "expected: " << expected;
   CHECK_EQ(leaf->get().text(), expected);
 }
diff --git a/verible/verilog/analysis/checkers/BUILD b/verible/verilog/analysis/checkers/BUILD
index 98178d9..5ecdd20 100644
--- a/verible/verilog/analysis/checkers/BUILD
+++ b/verible/verilog/analysis/checkers/BUILD
@@ -931,6 +931,7 @@
         "//verible/common/text:symbol",
         "//verible/common/text:syntax-tree-context",
         "//verible/common/text:token-info",
+        "//verible/common/text:tree-utils",
         "//verible/common/util:logging",
         "//verible/verilog/CST:numbers",
         "//verible/verilog/CST:verilog-matchers",
@@ -971,6 +972,7 @@
         "//verible/common/text:symbol",
         "//verible/common/text:syntax-tree-context",
         "//verible/common/text:token-info",
+        "//verible/common/text:tree-utils",
         "//verible/verilog/CST:numbers",
         "//verible/verilog/CST:verilog-matchers",
         "//verible/verilog/analysis:descriptions",
@@ -1010,7 +1012,7 @@
         "//verible/common/text:symbol",
         "//verible/common/text:syntax-tree-context",
         "//verible/common/text:token-info",
-        "//verible/common/util:casts",
+        "//verible/common/text:tree-utils",
         "//verible/verilog/CST:expression",
         "//verible/verilog/CST:verilog-matchers",
         "//verible/verilog/CST:verilog-nonterminals",
@@ -1156,7 +1158,6 @@
         "//verible/common/text:symbol",
         "//verible/common/text:syntax-tree-context",
         "//verible/common/text:tree-utils",
-        "//verible/common/util:casts",
         "//verible/verilog/CST:verilog-matchers",
         "//verible/verilog/CST:verilog-nonterminals",
         "//verible/verilog/analysis:descriptions",
@@ -1195,7 +1196,7 @@
         "//verible/common/text:config-utils",
         "//verible/common/text:symbol",
         "//verible/common/text:syntax-tree-context",
-        "//verible/common/util:casts",
+        "//verible/common/text:tree-utils",
         "//verible/common/util:logging",
         "//verible/verilog/CST:verilog-matchers",
         "//verible/verilog/CST:verilog-nonterminals",
diff --git a/verible/verilog/analysis/checkers/always-comb-blocking-rule.cc b/verible/verilog/analysis/checkers/always-comb-blocking-rule.cc
index 0988b8d..68e0509 100644
--- a/verible/verilog/analysis/checkers/always-comb-blocking-rule.cc
+++ b/verible/verilog/analysis/checkers/always-comb-blocking-rule.cc
@@ -27,7 +27,6 @@
 #include "verible/common/text/symbol.h"
 #include "verible/common/text/syntax-tree-context.h"
 #include "verible/common/text/tree-utils.h"
-#include "verible/common/util/casts.h"
 #include "verible/verilog/CST/verilog-matchers.h"  // IWYU pragma: keep
 #include "verible/verilog/CST/verilog-nonterminals.h"
 #include "verible/verilog/analysis/descriptions.h"
@@ -38,7 +37,6 @@
 namespace analysis {
 
 using verible::AutoFix;
-using verible::down_cast;
 using verible::LintRuleStatus;
 using verible::LintViolation;
 using verible::SearchSyntaxTree;
@@ -77,8 +75,8 @@
          SearchSyntaxTree(symbol, NodekNonblockingAssignmentStatement())) {
       if (match.match->Kind() != verible::SymbolKind::kNode) continue;
 
-      const auto *node =
-          down_cast<const verible::SyntaxTreeNode *>(match.match);
+      const verible::SyntaxTreeNode *node = verible::MaybeNode(match.match);
+      if (!node) return;
 
       const verible::SyntaxTreeLeaf *leaf = verible::GetSubtreeAsLeaf(
           *node, NodeEnum::kNonblockingAssignmentStatement, 1);
diff --git a/verible/verilog/analysis/checkers/always-ff-non-blocking-rule.cc b/verible/verilog/analysis/checkers/always-ff-non-blocking-rule.cc
index 3b0a4db..4922c52 100644
--- a/verible/verilog/analysis/checkers/always-ff-non-blocking-rule.cc
+++ b/verible/verilog/analysis/checkers/always-ff-non-blocking-rule.cc
@@ -29,7 +29,7 @@
 #include "verible/common/text/config-utils.h"
 #include "verible/common/text/symbol.h"
 #include "verible/common/text/syntax-tree-context.h"
-#include "verible/common/util/casts.h"
+#include "verible/common/text/tree-utils.h"
 #include "verible/common/util/logging.h"
 #include "verible/verilog/CST/verilog-matchers.h"
 #include "verible/verilog/CST/verilog-nonterminals.h"
@@ -108,22 +108,18 @@
 
   verible::matcher::BoundSymbolManager symbol_man;
   if (asgn_blocking_matcher.Matches(symbol, &symbol_man)) {
-    if (const auto *const node =
-            verible::down_cast<const verible::SyntaxTreeNode *>(&symbol)) {
-      check_root =
-          /* lhs */ verible::down_cast<const verible::SyntaxTreeNode *>(
-              node->front().get());
+    if (const verible::SyntaxTreeNode *const node =
+            verible::MaybeNode(&symbol)) {
+      check_root = /* lhs */ verible::MaybeNode(node->front().get());
     }
   } else {
     // Not interested in any other blocking assignments unless flagged
     if (!catch_modifying_assignments_) return;
 
     if (asgn_modify_matcher.Matches(symbol, &symbol_man)) {
-      if (const auto *const node =
-              verible::down_cast<const verible::SyntaxTreeNode *>(&symbol)) {
-        check_root =
-            /* lhs */ verible::down_cast<const verible::SyntaxTreeNode *>(
-                node->front().get());
+      if (const verible::SyntaxTreeNode *const node =
+              verible::MaybeNode(&symbol)) {
+        check_root = /* lhs */ verible::MaybeNode(node->front().get());
       }
     } else if (asgn_incdec_matcher.Matches(symbol, &symbol_man)) {
       check_root = &symbol;
@@ -144,11 +140,9 @@
       if (var.context.IsInside(NodeEnum::kHierarchyExtension)) continue;
 
       bool found = false;
-      if (const auto *const varn =
-              verible::down_cast<const verible::SyntaxTreeNode *>(var.match)) {
-        if (const auto *const ident =
-                verible::down_cast<const verible::SyntaxTreeLeaf *>(
-                    varn->front().get())) {
+      if (const verible::SyntaxTreeNode *const varn =
+              verible::MaybeNode(var.match)) {
+        if (const auto *const ident = verible::MaybeLeaf(varn->front().get())) {
           found = std::find(locals_.begin(), locals_.end(),
                             ident->get().text()) != locals_.end();
           VLOG(4) << "LHS='" << ident->get().text() << "' FOUND=" << found
@@ -210,11 +204,10 @@
   if (decl_matcher.Matches(symbol, &symbol_man)) {
     auto &count = scopes_.top().inherited_local_count;
     for (const auto &var : SearchSyntaxTree(symbol, var_matcher)) {
-      if (const auto *const node =
-              verible::down_cast<const verible::SyntaxTreeNode *>(var.match)) {
-        if (const auto *const ident =
-                verible::down_cast<const verible::SyntaxTreeLeaf *>(
-                    node->front().get())) {
+      if (const verible::SyntaxTreeNode *const node =
+              verible::MaybeNode(var.match)) {
+        if (const verible::SyntaxTreeLeaf *const ident =
+                verible::MaybeLeaf(node->front().get())) {
           const std::string_view name = ident->get().text();
           VLOG(4) << "Registering '" << name << '\'' << std::endl;
           locals_.emplace_back(name);
diff --git a/verible/verilog/analysis/checkers/create-object-name-match-rule.cc b/verible/verilog/analysis/checkers/create-object-name-match-rule.cc
index 9e5fed9..cc014f4 100644
--- a/verible/verilog/analysis/checkers/create-object-name-match-rule.cc
+++ b/verible/verilog/analysis/checkers/create-object-name-match-rule.cc
@@ -29,7 +29,7 @@
 #include "verible/common/text/symbol.h"
 #include "verible/common/text/syntax-tree-context.h"
 #include "verible/common/text/token-info.h"
-#include "verible/common/util/casts.h"
+#include "verible/common/text/tree-utils.h"
 #include "verible/verilog/CST/expression.h"
 #include "verible/verilog/CST/verilog-matchers.h"
 #include "verible/verilog/CST/verilog-nonterminals.h"
@@ -40,7 +40,6 @@
 namespace verilog {
 namespace analysis {
 
-using verible::down_cast;
 using verible::LintRuleStatus;
 using verible::LintViolation;
 using verible::SyntaxTreeContext;
@@ -89,8 +88,7 @@
   if (node.MatchesTag(NodeEnum::kUnqualifiedId)) {
     if (!node.empty()) {
       // The one-and-only child is the SymbolIdentifier token
-      const auto &leaf_ptr =
-          down_cast<const SyntaxTreeLeaf *>(node.front().get());
+      const SyntaxTreeLeaf *leaf_ptr = verible::MaybeLeaf(node.front().get());
       if (leaf_ptr != nullptr) {
         const TokenInfo &token = leaf_ptr->get();
         return token.token_enum() == SymbolIdentifier && token.text() == name;
@@ -109,10 +107,11 @@
   // my_pkg::class_type::type_id::create.
   // 5: 3 segments + 2 separators (in alternation), e.g. A::B::C
   if (qualified_id_node.size() >= 5) {
-    const auto *create_leaf_ptr =
-        down_cast<const SyntaxTreeNode *>(qualified_id_node.back().get());
-    const auto *type_id_leaf_ptr = down_cast<const SyntaxTreeNode *>(
-        qualified_id_node[num_children - 3].get());
+    // TODO: naming is off. These are not leafs
+    const SyntaxTreeNode *create_leaf_ptr =
+        verible::MaybeNode(qualified_id_node.back().get());
+    const SyntaxTreeNode *type_id_leaf_ptr =
+        verible::MaybeNode(qualified_id_node[num_children - 3].get());
     if (create_leaf_ptr != nullptr && type_id_leaf_ptr != nullptr) {
       return UnqualifiedIdEquals(*create_leaf_ptr, "create") &&
              UnqualifiedIdEquals(*type_id_leaf_ptr, "type_id");
@@ -138,12 +137,7 @@
   if (!expr_node.MatchesTag(NodeEnum::kExpression)) return nullptr;
 
   // this check is limited to only checking string literal leaf tokens
-  if (expr_node.front().get()->Kind() != verible::SymbolKind::kLeaf) {
-    return nullptr;
-  }
-
-  const auto *leaf_ptr =
-      down_cast<const SyntaxTreeLeaf *>(expr_node.front().get());
+  const SyntaxTreeLeaf *leaf_ptr = verible::MaybeLeaf(expr_node.front().get());
   if (leaf_ptr != nullptr) {
     const TokenInfo &token = leaf_ptr->get();
     if (token.token_enum() == TK_StringLiteral) {
@@ -158,8 +152,8 @@
     const SyntaxTreeNode &args_node) {
   if (!args_node.empty()) {
     const auto &first_arg = args_node.front();
-    if (const auto *first_expr =
-            down_cast<const SyntaxTreeNode *>(first_arg.get())) {
+    if (const SyntaxTreeNode *first_expr =
+            verible::MaybeNode(first_arg.get())) {
       return first_expr;
     }
   }
@@ -183,15 +177,15 @@
 
   // Extract named bindings for matched nodes within this match.
 
-  const auto *lval_ref = manager.GetAs<SyntaxTreeNode>("lval_ref");
+  const SyntaxTreeNode *lval_ref = manager.GetAsNode("lval_ref");
   if (lval_ref == nullptr) return;
 
   const TokenInfo *lval_id = ReferenceIsSimpleIdentifier(*lval_ref);
   if (lval_id == nullptr) return;
   if (lval_id->token_enum() != SymbolIdentifier) return;
 
-  const auto *call = manager.GetAs<SyntaxTreeNode>("func");
-  const auto *args = manager.GetAs<SyntaxTreeNode>("args");
+  const SyntaxTreeNode *call = manager.GetAsNode("func");
+  const SyntaxTreeNode *args = manager.GetAsNode("args");
   if (call == nullptr) return;
   if (args == nullptr) return;
   if (!QualifiedCallIsTypeIdCreate(*call)) return;
diff --git a/verible/verilog/analysis/checkers/forbidden-macro-rule.cc b/verible/verilog/analysis/checkers/forbidden-macro-rule.cc
index e403106..34c3da1 100644
--- a/verible/verilog/analysis/checkers/forbidden-macro-rule.cc
+++ b/verible/verilog/analysis/checkers/forbidden-macro-rule.cc
@@ -71,7 +71,7 @@
     const verible::Symbol &symbol, const verible::SyntaxTreeContext &context) {
   verible::matcher::BoundSymbolManager manager;
   if (MacroCallMatcher().Matches(symbol, &manager)) {
-    if (const auto *leaf = manager.GetAs<verible::SyntaxTreeLeaf>("name")) {
+    if (const verible::SyntaxTreeLeaf *leaf = manager.GetAsLeaf("name")) {
       const auto &imm = InvalidMacrosMap();
       if (imm.find(std::string(leaf->get().text())) != imm.end()) {
         violations_.insert(
diff --git a/verible/verilog/analysis/checkers/forbidden-symbol-rule.cc b/verible/verilog/analysis/checkers/forbidden-symbol-rule.cc
index 24d0580..04558ea 100644
--- a/verible/verilog/analysis/checkers/forbidden-symbol-rule.cc
+++ b/verible/verilog/analysis/checkers/forbidden-symbol-rule.cc
@@ -79,7 +79,7 @@
     const verible::Symbol &symbol, const verible::SyntaxTreeContext &context) {
   verible::matcher::BoundSymbolManager manager;
   if (IdMatcher().Matches(symbol, &manager)) {
-    if (const auto *leaf = manager.GetAs<verible::SyntaxTreeLeaf>("name")) {
+    if (const verible::SyntaxTreeLeaf *leaf = manager.GetAsLeaf("name")) {
       const auto &ism = InvalidSymbolsMap();
       if (ism.find(std::string(leaf->get().text())) != ism.end()) {
         violations_.insert(
diff --git a/verible/verilog/analysis/checkers/module-instantiation-rules.cc b/verible/verilog/analysis/checkers/module-instantiation-rules.cc
index 1639ef2..9a850e5 100644
--- a/verible/verilog/analysis/checkers/module-instantiation-rules.cc
+++ b/verible/verilog/analysis/checkers/module-instantiation-rules.cc
@@ -92,16 +92,14 @@
 }
 
 static bool IsComma(const verible::Symbol &symbol) {
-  if (symbol.Kind() == verible::SymbolKind::kLeaf) {
-    const auto *leaf = down_cast<const verible::SyntaxTreeLeaf *>(&symbol);
-    if (leaf) return leaf->get().token_enum() == ',';
-  }
+  const verible::SyntaxTreeLeaf *leaf = verible::MaybeLeaf(&symbol);
+  if (leaf) return leaf->get().token_enum() == ',';
   return false;
 }
 
 static bool IsAnyPort(const verible::Symbol *symbol) {
-  if (symbol->Kind() == verible::SymbolKind::kNode) {
-    const auto *node = down_cast<const verible::SyntaxTreeNode *>(symbol);
+  const verible::SyntaxTreeNode *node = verible::MaybeNode(symbol);
+  if (node) {
     return node->MatchesTag(NodeEnum::kActualNamedPort) ||
            node->MatchesTag(NodeEnum::kActualPositionalPort);
   }
@@ -125,7 +123,7 @@
 
   verible::matcher::BoundSymbolManager manager;
   if (ParamsMatcher().Matches(symbol, &manager)) {
-    if (const auto *list = manager.GetAs<verible::SyntaxTreeNode>("list")) {
+    if (const verible::SyntaxTreeNode *list = manager.GetAsNode("list")) {
       const auto &children = list->children();
       auto parameter_count = std::count_if(
           children.begin(), children.end(),
@@ -159,8 +157,7 @@
   verible::matcher::BoundSymbolManager manager;
 
   if (InstanceMatcher().Matches(symbol, &manager)) {
-    if (const auto *port_list_node =
-            manager.GetAs<verible::SyntaxTreeNode>("list")) {
+    if (const auto *port_list_node = manager.GetAsNode("list")) {
       // Don't know how to handle unexpected non-portlist, so proceed
       if (!port_list_node->MatchesTag(NodeEnum::kPortActualList)) return;
 
diff --git a/verible/verilog/analysis/checkers/plusarg-assignment-rule.cc b/verible/verilog/analysis/checkers/plusarg-assignment-rule.cc
index bcae10b..cc027e6 100644
--- a/verible/verilog/analysis/checkers/plusarg-assignment-rule.cc
+++ b/verible/verilog/analysis/checkers/plusarg-assignment-rule.cc
@@ -61,7 +61,7 @@
     const verible::Symbol &symbol, const verible::SyntaxTreeContext &context) {
   verible::matcher::BoundSymbolManager manager;
   if (IdMatcher().Matches(symbol, &manager)) {
-    if (const auto *leaf = manager.GetAs<verible::SyntaxTreeLeaf>("name")) {
+    if (const verible::SyntaxTreeLeaf *leaf = manager.GetAsLeaf("name")) {
       if (kForbiddenFunctionName == leaf->get().text()) {
         violations_.insert(
             verible::LintViolation(leaf->get(), FormatReason(), context));
diff --git a/verible/verilog/analysis/checkers/truncated-numeric-literal-rule.cc b/verible/verilog/analysis/checkers/truncated-numeric-literal-rule.cc
index 8c24163..298bc6c 100644
--- a/verible/verilog/analysis/checkers/truncated-numeric-literal-rule.cc
+++ b/verible/verilog/analysis/checkers/truncated-numeric-literal-rule.cc
@@ -33,6 +33,7 @@
 #include "verible/common/text/symbol.h"
 #include "verible/common/text/syntax-tree-context.h"
 #include "verible/common/text/token-info.h"
+#include "verible/common/text/tree-utils.h"
 #include "verible/verilog/CST/numbers.h"
 #include "verible/verilog/CST/verilog-matchers.h"
 #include "verible/verilog/analysis/descriptions.h"
@@ -41,7 +42,6 @@
 namespace verilog {
 namespace analysis {
 
-using verible::down_cast;
 using verible::LintRuleStatus;
 using verible::LintViolation;
 using verible::SyntaxTreeContext;
@@ -152,18 +152,17 @@
     const verible::Symbol &symbol, const SyntaxTreeContext &context) {
   verible::matcher::BoundSymbolManager manager;
   if (!NumberMatcher().Matches(symbol, &manager)) return;
-  const auto *width_leaf = manager.GetAs<SyntaxTreeLeaf>("width");
-  const auto *literal_node = manager.GetAs<SyntaxTreeNode>("literal");
+  const SyntaxTreeLeaf *width_leaf = manager.GetAsLeaf("width");
+  const SyntaxTreeNode *literal_node = manager.GetAsNode("literal");
   if (!width_leaf || !literal_node) return;
 
-  const auto width_text = width_leaf->get().text();
+  const std::string_view width_text = width_leaf->get().text();
   size_t width;
   if (!absl::SimpleAtoi(width_text, &width)) return;
 
-  const auto *base_leaf =
-      down_cast<const SyntaxTreeLeaf *>((*literal_node)[0].get());
-  const auto *digits_leaf =
-      down_cast<const SyntaxTreeLeaf *>((*literal_node)[1].get());
+  const auto *base_leaf = verible::MaybeLeaf((*literal_node)[0].get());
+  const auto *digits_leaf = verible::MaybeLeaf((*literal_node)[1].get());
+  if (!base_leaf || !digits_leaf) return;
 
   const auto base_text = base_leaf->get().text();
   const auto digits_text = digits_leaf->get().text();
diff --git a/verible/verilog/analysis/checkers/undersized-binary-literal-rule.cc b/verible/verilog/analysis/checkers/undersized-binary-literal-rule.cc
index 2269fff..ffc7c67 100644
--- a/verible/verilog/analysis/checkers/undersized-binary-literal-rule.cc
+++ b/verible/verilog/analysis/checkers/undersized-binary-literal-rule.cc
@@ -33,6 +33,7 @@
 #include "verible/common/text/symbol.h"
 #include "verible/common/text/syntax-tree-context.h"
 #include "verible/common/text/token-info.h"
+#include "verible/common/text/tree-utils.h"
 #include "verible/common/util/logging.h"
 #include "verible/verilog/CST/numbers.h"
 #include "verible/verilog/CST/verilog-matchers.h"
@@ -43,12 +44,10 @@
 namespace analysis {
 
 using verible::AutoFix;
-using verible::down_cast;
 using verible::LintRuleStatus;
 using verible::LintViolation;
 using verible::SyntaxTreeContext;
 using verible::SyntaxTreeLeaf;
-using verible::SyntaxTreeNode;
 using verible::matcher::Matcher;
 
 // Register UndersizedBinaryLiteralRule
@@ -90,18 +89,19 @@
     const verible::Symbol &symbol, const SyntaxTreeContext &context) {
   verible::matcher::BoundSymbolManager manager;
   if (!NumberMatcher().Matches(symbol, &manager)) return;
-  const auto *width_leaf = manager.GetAs<SyntaxTreeLeaf>("width");
-  const auto *literal_node = manager.GetAs<SyntaxTreeNode>("literal");
+  const verible::SyntaxTreeLeaf *width_leaf = manager.GetAsLeaf("width");
+  const verible::SyntaxTreeNode *literal_node = manager.GetAsNode("literal");
   if (!width_leaf || !literal_node) return;
 
   const auto width_text = width_leaf->get().text();
   size_t width;
   if (!absl::SimpleAtoi(width_text, &width)) return;
 
-  const auto *base_leaf =
-      down_cast<const SyntaxTreeLeaf *>((*literal_node)[0].get());
-  const auto *digits_leaf =
-      down_cast<const SyntaxTreeLeaf *>((*literal_node)[1].get());
+  const SyntaxTreeLeaf *base_leaf =
+      verible::MaybeLeaf((*literal_node)[0].get());
+  const SyntaxTreeLeaf *digits_leaf =
+      verible::MaybeLeaf((*literal_node)[1].get());
+  if (!base_leaf || !digits_leaf) return;
 
   const auto base_text = base_leaf->get().text();
   const auto digits_text = digits_leaf->get().text();
diff --git a/verible/verilog/analysis/checkers/v2001-generate-begin-rule.cc b/verible/verilog/analysis/checkers/v2001-generate-begin-rule.cc
index ad7cd04..8d4b63b 100644
--- a/verible/verilog/analysis/checkers/v2001-generate-begin-rule.cc
+++ b/verible/verilog/analysis/checkers/v2001-generate-begin-rule.cc
@@ -63,7 +63,7 @@
     const verible::Symbol &symbol, const verible::SyntaxTreeContext &context) {
   verible::matcher::BoundSymbolManager manager;
   if (GenerateRegionMatcher().Matches(symbol, &manager)) {
-    if (const auto *block = manager.GetAs<verible::SyntaxTreeNode>("block")) {
+    if (const verible::SyntaxTreeNode *block = manager.GetAsNode("block")) {
       violations_.insert(LintViolation(verible::GetLeftmostLeaf(*block)->get(),
                                        kMessage, context));
     }
diff --git a/verible/verilog/analysis/checkers/void-cast-rule.cc b/verible/verilog/analysis/checkers/void-cast-rule.cc
index 724e682..9965d1d 100644
--- a/verible/verilog/analysis/checkers/void-cast-rule.cc
+++ b/verible/verilog/analysis/checkers/void-cast-rule.cc
@@ -38,8 +38,6 @@
 using verible::LintRuleStatus;
 using verible::LintViolation;
 using verible::SyntaxTreeContext;
-using verible::SyntaxTreeLeaf;
-using verible::SyntaxTreeNode;
 using verible::matcher::Matcher;
 
 // Register VoidCastRule
@@ -98,8 +96,7 @@
   // Check for forbidden function names
   verible::matcher::BoundSymbolManager manager;
   if (FunctionMatcher().Matches(symbol, &manager)) {
-    if (const auto *function_id =
-            manager.GetAs<verible::SyntaxTreeLeaf>("id")) {
+    if (const verible::SyntaxTreeLeaf *function_id = manager.GetAsLeaf("id")) {
       const auto &bfs = ForbiddenFunctionsSet();
       if (bfs.find(std::string(function_id->get().text())) != bfs.end()) {
         violations_.insert(LintViolation(function_id->get(),
@@ -111,8 +108,7 @@
   // Check for forbidden calls to randomize
   manager.Clear();
   if (RandomizeMatcher().Matches(symbol, &manager)) {
-    if (const auto *randomize_node =
-            manager.GetAs<verible::SyntaxTreeNode>("id")) {
+    if (const auto *randomize_node = manager.GetAsNode("id")) {
       const auto *leaf_ptr = verible::GetLeftmostLeaf(*randomize_node);
       const verible::TokenInfo token = ABSL_DIE_IF_NULL(leaf_ptr)->get();
       violations_.insert(LintViolation(
diff --git a/verible/verilog/formatting/BUILD b/verible/verilog/formatting/BUILD
index 0940ef8..929e592 100644
--- a/verible/verilog/formatting/BUILD
+++ b/verible/verilog/formatting/BUILD
@@ -30,7 +30,6 @@
         "//verible/common/text:token-info",
         "//verible/common/text:tree-context-visitor",
         "//verible/common/text:tree-utils",
-        "//verible/common/util:casts",
         "//verible/common/util:logging",
         "//verible/common/util:value-saver",
         "//verible/verilog/CST:context-functions",
diff --git a/verible/verilog/formatting/align.cc b/verible/verilog/formatting/align.cc
index de4cd89..55d8952 100644
--- a/verible/verilog/formatting/align.cc
+++ b/verible/verilog/formatting/align.cc
@@ -32,7 +32,6 @@
 #include "verible/common/text/token-info.h"
 #include "verible/common/text/tree-context-visitor.h"
 #include "verible/common/text/tree-utils.h"
-#include "verible/common/util/casts.h"
 #include "verible/common/util/logging.h"
 #include "verible/common/util/value-saver.h"
 #include "verible/verilog/CST/context-functions.h"
@@ -52,7 +51,6 @@
 using verible::AlignmentGroupAction;
 using verible::ByteOffsetSet;
 using verible::ColumnSchemaScanner;
-using verible::down_cast;
 using verible::ExtractAlignmentGroupsFunction;
 using verible::FormatTokenRange;
 using verible::PreFormatToken;
@@ -1551,7 +1549,7 @@
   const auto *origin = uwline.Origin();
   VLOG(2) << "origin is nullptr? " << (origin == nullptr);
   if (origin == nullptr) return;
-  const auto *node = down_cast<const SyntaxTreeNode *>(origin);
+  const SyntaxTreeNode *node = verible::MaybeNode(origin);
   VLOG(2) << "origin is node? " << (node != nullptr);
   if (node == nullptr) return;
   // Dispatch aligning function based on syntax tree node type.