ast: Move Module function methods to FunctionList

Module will be split into Module (immutable) and ModuleBuilder (mutable).
By moving these methods to the FunctionList, we can deduplicate a bunch of common logic.

Bug: tint:390
Change-Id: I3fd85200aae4e8dc3d5afce8c9aaa6512809a3a0
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/38363
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/ast/function.cc b/src/ast/function.cc
index 88b5b96..66147f9 100644
--- a/src/ast/function.cc
+++ b/src/ast/function.cc
@@ -360,5 +360,32 @@
   return ret;
 }
 
+Function* FunctionList::Find(Symbol sym) const {
+  for (auto* func : *this) {
+    if (func->symbol() == sym) {
+      return func;
+    }
+  }
+  return nullptr;
+}
+
+Function* FunctionList::Find(Symbol sym, PipelineStage stage) const {
+  for (auto* func : *this) {
+    if (func->symbol() == sym && func->pipeline_stage() == stage) {
+      return func;
+    }
+  }
+  return nullptr;
+}
+
+bool FunctionList::HasStage(ast::PipelineStage stage) const {
+  for (auto* func : *this) {
+    if (func->pipeline_stage() == stage) {
+      return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace ast
 }  // namespace tint
diff --git a/src/ast/function.h b/src/ast/function.h
index 248dd55..0f635c1 100644
--- a/src/ast/function.h
+++ b/src/ast/function.h
@@ -210,7 +210,28 @@
 };
 
 /// A list of functions
-using FunctionList = std::vector<Function*>;
+class FunctionList : public std::vector<Function*> {
+ public:
+  /// Appends f to the end of the list
+  /// @param f the function to append to this list
+  void Add(Function* f) { this->emplace_back(f); }
+
+  /// Returns the function with the given name
+  /// @param sym the function symbol to search for
+  /// @returns the associated function or nullptr if none exists
+  Function* Find(Symbol sym) const;
+
+  /// Returns the function with the given name
+  /// @param sym the function symbol to search for
+  /// @param stage the pipeline stage
+  /// @returns the associated function or nullptr if none exists
+  Function* Find(Symbol sym, PipelineStage stage) const;
+
+  /// @param stage the pipeline stage
+  /// @returns true if the Builder contains an entrypoint function with
+  /// the given stage
+  bool HasStage(PipelineStage stage) const;
+};
 
 }  // namespace ast
 }  // namespace tint
diff --git a/src/ast/function_test.cc b/src/ast/function_test.cc
index 548aedc..a2aeb5d 100644
--- a/src/ast/function_test.cc
+++ b/src/ast/function_test.cc
@@ -18,6 +18,7 @@
 #include "src/ast/discard_statement.h"
 #include "src/ast/location_decoration.h"
 #include "src/ast/pipeline_stage.h"
+#include "src/ast/stage_decoration.h"
 #include "src/ast/test_helper.h"
 #include "src/ast/variable.h"
 #include "src/ast/workgroup_decoration.h"
@@ -356,6 +357,58 @@
   EXPECT_EQ(z, 6u);
 }
 
+using FunctionListTest = TestHelper;
+
+TEST_F(FunctionListTest, FindSymbol) {
+  auto* func = Func("main", VariableList{}, ty.f32, StatementList{},
+                    ast::FunctionDecorationList{});
+  FunctionList list;
+  list.Add(func);
+  EXPECT_EQ(func, list.Find(mod->RegisterSymbol("main")));
+}
+
+TEST_F(FunctionListTest, FindSymbolMissing) {
+  FunctionList list;
+  EXPECT_EQ(nullptr, list.Find(mod->RegisterSymbol("Missing")));
+}
+
+TEST_F(FunctionListTest, FindSymbolStage) {
+  auto* fs = Func("main", VariableList{}, ty.f32, StatementList{},
+                  ast::FunctionDecorationList{
+                      create<ast::StageDecoration>(PipelineStage::kFragment),
+                  });
+  auto* vs = Func("main", VariableList{}, ty.f32, StatementList{},
+                  ast::FunctionDecorationList{
+                      create<ast::StageDecoration>(PipelineStage::kVertex),
+                  });
+  FunctionList list;
+  list.Add(fs);
+  list.Add(vs);
+  EXPECT_EQ(fs,
+            list.Find(mod->RegisterSymbol("main"), PipelineStage::kFragment));
+  EXPECT_EQ(vs, list.Find(mod->RegisterSymbol("main"), PipelineStage::kVertex));
+}
+
+TEST_F(FunctionListTest, FindSymbolStageMissing) {
+  FunctionList list;
+  list.Add(Func("main", VariableList{}, ty.f32, StatementList{},
+                ast::FunctionDecorationList{
+                    create<ast::StageDecoration>(PipelineStage::kFragment),
+                }));
+  EXPECT_EQ(nullptr,
+            list.Find(mod->RegisterSymbol("main"), PipelineStage::kVertex));
+}
+
+TEST_F(FunctionListTest, HasStage) {
+  FunctionList list;
+  list.Add(Func("main", VariableList{}, ty.f32, StatementList{},
+                ast::FunctionDecorationList{
+                    create<ast::StageDecoration>(PipelineStage::kFragment),
+                }));
+  EXPECT_TRUE(list.HasStage(PipelineStage::kFragment));
+  EXPECT_FALSE(list.HasStage(PipelineStage::kVertex));
+}
+
 }  // namespace
 }  // namespace ast
 }  // namespace tint
diff --git a/src/ast/module.cc b/src/ast/module.cc
index e439a8d..0a73dd0 100644
--- a/src/ast/module.cc
+++ b/src/ast/module.cc
@@ -48,34 +48,6 @@
   }
 }
 
-Function* Module::FindFunctionBySymbol(Symbol sym) const {
-  for (auto* func : functions_) {
-    if (func->symbol() == sym) {
-      return func;
-    }
-  }
-  return nullptr;
-}
-
-Function* Module::FindFunctionBySymbolAndStage(Symbol sym,
-                                               PipelineStage stage) const {
-  for (auto* func : functions_) {
-    if (func->symbol() == sym && func->pipeline_stage() == stage) {
-      return func;
-    }
-  }
-  return nullptr;
-}
-
-bool Module::HasStage(ast::PipelineStage stage) const {
-  for (auto* func : functions_) {
-    if (func->pipeline_stage() == stage) {
-      return true;
-    }
-  }
-  return false;
-}
-
 Symbol Module::RegisterSymbol(const std::string& name) {
   return symbol_table_.Register(name);
 }
diff --git a/src/ast/module.h b/src/ast/module.h
index 798a761..393f3db 100644
--- a/src/ast/module.h
+++ b/src/ast/module.h
@@ -82,24 +82,11 @@
     return constructed_types_;
   }
 
-  /// Adds a function to the module
-  /// @param func the function
-  void AddFunction(Function* func) { functions_.push_back(func); }
-  /// @returns the modules functions
-  const FunctionList& functions() const { return functions_; }
-  /// Returns the function with the given name
-  /// @param sym the function symbol to search for
-  /// @returns the associated function or nullptr if none exists
-  Function* FindFunctionBySymbol(Symbol sym) const;
-  /// Returns the function with the given name
-  /// @param sym the function symbol to search for
-  /// @param stage the pipeline stage
-  /// @returns the associated function or nullptr if none exists
-  Function* FindFunctionBySymbolAndStage(Symbol sym, PipelineStage stage) const;
-  /// @param stage the pipeline stage
-  /// @returns true if the module contains an entrypoint function with the given
-  /// stage
-  bool HasStage(PipelineStage stage) const;
+  /// @returns the functions declared in the translation unit
+  const FunctionList& Functions() const { return functions_; }
+
+  /// @returns the functions declared in the translation unit
+  FunctionList& Functions() { return functions_; }
 
   /// @returns true if all required fields in the AST are present.
   bool IsValid() const;
diff --git a/src/ast/module_test.cc b/src/ast/module_test.cc
index 605bdb8..399a442 100644
--- a/src/ast/module_test.cc
+++ b/src/ast/module_test.cc
@@ -32,7 +32,7 @@
 using ModuleTest = TestHelper;
 
 TEST_F(ModuleTest, Creation) {
-  EXPECT_EQ(mod->functions().size(), 0u);
+  EXPECT_EQ(mod->Functions().size(), 0u);
 }
 
 TEST_F(ModuleTest, ToStrEmitsPreambleAndPostamble) {
@@ -41,17 +41,6 @@
   EXPECT_EQ(str, expected);
 }
 
-TEST_F(ModuleTest, LookupFunction) {
-  auto* func = Func("main", VariableList{}, ty.f32, StatementList{},
-                    ast::FunctionDecorationList{});
-  mod->AddFunction(func);
-  EXPECT_EQ(func, mod->FindFunctionBySymbol(mod->RegisterSymbol("main")));
-}
-
-TEST_F(ModuleTest, LookupFunctionMissing) {
-  EXPECT_EQ(nullptr, mod->FindFunctionBySymbol(mod->RegisterSymbol("Missing")));
-}
-
 TEST_F(ModuleTest, IsValid_Empty) {
   EXPECT_TRUE(mod->IsValid());
 }
@@ -102,12 +91,12 @@
   auto* func = Func("main", VariableList(), ty.f32, StatementList{},
                     ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
   EXPECT_TRUE(mod->IsValid());
 }
 
 TEST_F(ModuleTest, IsValid_Null_Function) {
-  mod->AddFunction(nullptr);
+  mod->Functions().Add(nullptr);
   EXPECT_FALSE(mod->IsValid());
 }
 
@@ -115,7 +104,7 @@
   auto* func = Func("main", VariableList{}, nullptr, StatementList{},
                     ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
   EXPECT_FALSE(mod->IsValid());
 }
 
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
index 91d6cd1..dbbaa21 100644
--- a/src/inspector/inspector.cc
+++ b/src/inspector/inspector.cc
@@ -50,7 +50,7 @@
 std::vector<EntryPoint> Inspector::GetEntryPoints() {
   std::vector<EntryPoint> result;
 
-  for (auto* func : module_.functions()) {
+  for (auto* func : module_.Functions()) {
     if (!func->IsEntryPoint()) {
       continue;
     }
@@ -278,7 +278,7 @@
 }
 
 ast::Function* Inspector::FindEntryPointByName(const std::string& name) {
-  auto* func = module_.FindFunctionBySymbol(module_.GetSymbol(name));
+  auto* func = module_.Functions().Find(module_.GetSymbol(name));
   if (!func) {
     error_ += name + " was not found!";
     return nullptr;
diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc
index bd9ad5d..b0792bb 100644
--- a/src/inspector/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -701,7 +701,7 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, NoEntryPoints) {
-  mod->AddFunction(MakeEmptyBodyFunction("foo", {}));
+  mod->Functions().Add(MakeEmptyBodyFunction("foo", {}));
 
   auto result = inspector()->GetEntryPoints();
   ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
@@ -714,7 +714,7 @@
       "foo", ast::FunctionDecorationList{
                  create<ast::StageDecoration>(ast::PipelineStage::kVertex),
              });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   // TODO(dsinclair): Update to run the namer transform when available.
 
@@ -732,13 +732,13 @@
       "foo", ast::FunctionDecorationList{
                  create<ast::StageDecoration>(ast::PipelineStage::kVertex),
              });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   auto* bar = MakeEmptyBodyFunction(
       "bar", ast::FunctionDecorationList{
                  create<ast::StageDecoration>(ast::PipelineStage::kCompute),
              });
-  mod->AddFunction(bar);
+  mod->Functions().Add(bar);
 
   // TODO(dsinclair): Update to run the namer transform when available.
 
@@ -756,21 +756,21 @@
 
 TEST_F(InspectorGetEntryPointTest, MixFunctionsAndEntryPoints) {
   auto* func = MakeEmptyBodyFunction("func", {});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   auto* foo = MakeCallerBodyFunction(
       "foo", "func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   auto* bar = MakeCallerBodyFunction(
       "bar", "func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kFragment),
       });
-  mod->AddFunction(bar);
+  mod->Functions().Add(bar);
 
   // TODO(dsinclair): Update to run the namer transform when available.
 
@@ -792,7 +792,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   auto result = inspector()->GetEntryPoints();
   ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
@@ -811,7 +811,7 @@
                  create<ast::StageDecoration>(ast::PipelineStage::kCompute),
                  create<ast::WorkgroupDecoration>(8u, 2u, 1u),
              });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   auto result = inspector()->GetEntryPoints();
   ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
@@ -826,14 +826,14 @@
 
 TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
   auto* func = MakeEmptyBodyFunction("func", {});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   auto* foo = MakeCallerBodyFunction(
       "foo", "func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   auto result = inspector()->GetEntryPoints();
   ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
@@ -851,7 +851,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -875,14 +875,14 @@
 
   auto* func =
       MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}}, {});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   auto* foo = MakeCallerBodyFunction(
       "foo", "func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -906,14 +906,14 @@
 
   auto* func =
       MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}}, {});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   auto* foo = MakeInOutVariableCallerBodyFunction(
       "foo", "func", {{"in_var", "out_var"}},
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -940,7 +940,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -970,14 +970,14 @@
 
   auto* func = MakeInOutVariableBodyFunction(
       "func", {{"in_var", "out_var"}, {"in2_var", "out2_var"}}, {});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   auto* foo = MakeCallerBodyFunction(
       "foo", "func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1011,14 +1011,14 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   auto* bar = MakeInOutVariableBodyFunction(
       "bar", {{"in2_var", "out_var"}},
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kCompute),
       });
-  mod->AddFunction(bar);
+  mod->Functions().Add(bar);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1057,21 +1057,21 @@
 
   auto* func =
       MakeInOutVariableBodyFunction("func", {{"in2_var", "out2_var"}}, {});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   auto* foo = MakeInOutVariableCallerBodyFunction(
       "foo", "func", {{"in_var", "out_var"}},
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   auto* bar = MakeCallerBodyFunction(
       "bar", "func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kCompute),
       });
-  mod->AddFunction(bar);
+  mod->Functions().Add(bar);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1125,7 +1125,7 @@
 // TODO(rharrison): Reenable once GetRemappedNameForEntryPoint isn't a pass
 // through
 TEST_F(InspectorGetRemappedNameForEntryPointTest, DISABLED_NoEntryPoints) {
-  mod->AddFunction(MakeEmptyBodyFunction("foo", {}));
+  mod->Functions().Add(MakeEmptyBodyFunction("foo", {}));
 
   auto result = inspector()->GetRemappedNameForEntryPoint("foo");
   ASSERT_TRUE(inspector()->has_error());
@@ -1140,7 +1140,7 @@
       "foo", ast::FunctionDecorationList{
                  create<ast::StageDecoration>(ast::PipelineStage::kVertex),
              });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   // TODO(dsinclair): Update to run the namer transform when available.
 
@@ -1158,7 +1158,7 @@
       "foo", ast::FunctionDecorationList{
                  create<ast::StageDecoration>(ast::PipelineStage::kVertex),
              });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   // TODO(dsinclair): Update to run the namer transform when available.
 
@@ -1166,7 +1166,7 @@
       "bar", ast::FunctionDecorationList{
                  create<ast::StageDecoration>(ast::PipelineStage::kCompute),
              });
-  mod->AddFunction(bar);
+  mod->Functions().Add(bar);
 
   {
     auto result = inspector()->GetRemappedNameForEntryPoint("foo");
@@ -1284,14 +1284,14 @@
 
   auto* ub_func = MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
                                                           {{0, ty.i32}});
-  mod->AddFunction(ub_func);
+  mod->Functions().Add(ub_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "ub_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1312,14 +1312,14 @@
 
   auto* ub_func = MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
                                                           {{0, ty.i32}});
-  mod->AddFunction(ub_func);
+  mod->Functions().Add(ub_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "ub_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1337,14 +1337,14 @@
 
   auto* ub_func = MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
                                                           {{0, ty.i32}});
-  mod->AddFunction(ub_func);
+  mod->Functions().Add(ub_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "ub_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1366,14 +1366,14 @@
 
   auto* ub_func = MakeStructVariableReferenceBodyFunction(
       "ub_func", "foo_ub", {{0, ty.i32}, {1, ty.u32}, {2, ty.f32}});
-  mod->AddFunction(ub_func);
+  mod->Functions().Add(ub_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "ub_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1399,7 +1399,7 @@
                                  const std::string& var_name) {
     auto* ub_func = MakeStructVariableReferenceBodyFunction(
         func_name, var_name, {{0, ty.i32}, {1, ty.u32}, {2, ty.f32}});
-    mod->AddFunction(ub_func);
+    mod->Functions().Add(ub_func);
   };
   AddReferenceFunc("ub_foo_func", "ub_foo");
   AddReferenceFunc("ub_bar_func", "ub_bar");
@@ -1417,7 +1417,7 @@
            ast::FunctionDecorationList{
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1447,14 +1447,14 @@
 
   auto* ub_func = MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
                                                           {{0, ty.i32}});
-  mod->AddFunction(ub_func);
+  mod->Functions().Add(ub_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "ub_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1476,14 +1476,14 @@
 
   auto* sb_func = MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                                           {{0, ty.i32}});
-  mod->AddFunction(sb_func);
+  mod->Functions().Add(sb_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "sb_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1505,14 +1505,14 @@
 
   auto* sb_func = MakeStructVariableReferenceBodyFunction(
       "sb_func", "foo_sb", {{0, ty.i32}, {1, ty.u32}, {2, ty.f32}});
-  mod->AddFunction(sb_func);
+  mod->Functions().Add(sb_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "sb_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1538,7 +1538,7 @@
                                  const std::string& var_name) {
     auto* sb_func = MakeStructVariableReferenceBodyFunction(
         func_name, var_name, {{0, ty.i32}, {1, ty.u32}, {2, ty.f32}});
-    mod->AddFunction(sb_func);
+    mod->Functions().Add(sb_func);
   };
   AddReferenceFunc("sb_foo_func", "sb_foo");
   AddReferenceFunc("sb_bar_func", "sb_bar");
@@ -1559,7 +1559,7 @@
            ast::FunctionDecorationList{
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1589,14 +1589,14 @@
 
   auto* sb_func = MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                                           {{0, ty.i32}});
-  mod->AddFunction(sb_func);
+  mod->Functions().Add(sb_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "sb_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1618,14 +1618,14 @@
 
   auto* sb_func = MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                                           {{0, ty.i32}});
-  mod->AddFunction(sb_func);
+  mod->Functions().Add(sb_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "sb_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1647,14 +1647,14 @@
 
   auto* sb_func = MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                                           {{0, ty.i32}});
-  mod->AddFunction(sb_func);
+  mod->Functions().Add(sb_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "sb_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1672,14 +1672,14 @@
 
   auto* sb_func = MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                                           {{0, ty.i32}});
-  mod->AddFunction(sb_func);
+  mod->Functions().Add(sb_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "sb_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1707,7 +1707,7 @@
                                  const std::string& var_name) {
     auto* sb_func = MakeStructVariableReferenceBodyFunction(
         func_name, var_name, {{0, ty.i32}, {1, ty.u32}, {2, ty.f32}});
-    mod->AddFunction(sb_func);
+    mod->Functions().Add(sb_func);
   };
   AddReferenceFunc("sb_foo_func", "sb_foo");
   AddReferenceFunc("sb_bar_func", "sb_bar");
@@ -1728,7 +1728,7 @@
            ast::FunctionDecorationList{
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1759,14 +1759,14 @@
 
   auto* sb_func = MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                                           {{0, ty.i32}});
-  mod->AddFunction(sb_func);
+  mod->Functions().Add(sb_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "sb_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1790,14 +1790,14 @@
 
   auto* sb_func = MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                                           {{0, ty.i32}});
-  mod->AddFunction(sb_func);
+  mod->Functions().Add(sb_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "sb_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1820,14 +1820,14 @@
 
   auto* sb_func = MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                                           {{0, ty.i32}});
-  mod->AddFunction(sb_func);
+  mod->Functions().Add(sb_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "sb_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1849,7 +1849,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1866,7 +1866,7 @@
       "ep_func", ast::FunctionDecorationList{
                      create<ast::StageDecoration>(ast::PipelineStage::kVertex),
                  });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1885,14 +1885,14 @@
 
   auto* foo_func = MakeSamplerReferenceBodyFunction(
       "foo_func", "foo_texture", "foo_sampler", "foo_coords", ty.f32, {});
-  mod->AddFunction(foo_func);
+  mod->Functions().Add(foo_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "foo_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1916,7 +1916,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1936,7 +1936,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1958,7 +1958,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1975,7 +1975,7 @@
       "ep_func", ast::FunctionDecorationList{
                      create<ast::StageDecoration>(ast::PipelineStage::kVertex),
                  });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -1995,14 +1995,14 @@
   auto* foo_func = MakeComparisonSamplerReferenceBodyFunction(
       "foo_func", "foo_texture", "foo_sampler", "foo_coords", "foo_depth",
       ty.f32, {});
-  mod->AddFunction(foo_func);
+  mod->Functions().Add(foo_func);
 
   auto* ep_func = MakeCallerBodyFunction(
       "ep_func", "foo_func",
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(ep_func);
+  mod->Functions().Add(ep_func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -2026,7 +2026,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -2046,7 +2046,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -2061,7 +2061,7 @@
       "foo", ast::FunctionDecorationList{
                  create<ast::StageDecoration>(ast::PipelineStage::kVertex),
              });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   auto result = inspector()->GetSampledTextureResourceBindings("foo");
   ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
@@ -2084,7 +2084,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -2175,7 +2175,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -2246,7 +2246,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
@@ -2301,7 +2301,7 @@
       "foo", ast::FunctionDecorationList{
                  create<ast::StageDecoration>(ast::PipelineStage::kVertex),
              });
-  mod->AddFunction(foo);
+  mod->Functions().Add(foo);
 
   auto result = inspector()->GetSampledTextureResourceBindings("foo");
   ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
@@ -2326,7 +2326,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
 
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 00d7545..30daec5 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -859,7 +859,7 @@
 
   auto& statements = statements_stack_[0].GetStatements();
   auto* body = create<ast::BlockStatement>(Source{}, statements);
-  ast_module_.AddFunction(
+  ast_module_.Functions().Add(
       create<ast::Function>(decl.source, ast_module_.RegisterSymbol(decl.name),
                             std::move(decl.params), decl.return_type, body,
                             std::move(decl.decorations)));
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 7816725..9521365 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -378,7 +378,7 @@
   if (func.errored)
     errored = true;
   if (func.matched) {
-    module_.AddFunction(func.value);
+    module_.Functions().Add(func.value);
     return true;
   }
 
diff --git a/src/reader/wgsl/parser_impl_global_decl_test.cc b/src/reader/wgsl/parser_impl_global_decl_test.cc
index 7fac54c..3875ca0 100644
--- a/src/reader/wgsl/parser_impl_global_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_decl_test.cc
@@ -135,8 +135,8 @@
   ASSERT_FALSE(p->has_error()) << p->error();
 
   auto& m = p->get_module();
-  ASSERT_EQ(m.functions().size(), 1u);
-  EXPECT_EQ(m.SymbolToName(m.functions()[0]->symbol()), "main");
+  ASSERT_EQ(m.Functions().size(), 1u);
+  EXPECT_EQ(m.SymbolToName(m.Functions()[0]->symbol()), "main");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_Function_WithDecoration) {
@@ -145,8 +145,8 @@
   ASSERT_FALSE(p->has_error()) << p->error();
 
   auto& m = p->get_module();
-  ASSERT_EQ(m.functions().size(), 1u);
-  EXPECT_EQ(m.SymbolToName(m.functions()[0]->symbol()), "main");
+  ASSERT_EQ(m.Functions().size(), 1u);
+  EXPECT_EQ(m.SymbolToName(m.Functions()[0]->symbol()), "main");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_Function_Invalid) {
diff --git a/src/reader/wgsl/parser_impl_test.cc b/src/reader/wgsl/parser_impl_test.cc
index 1c21208..3065a08 100644
--- a/src/reader/wgsl/parser_impl_test.cc
+++ b/src/reader/wgsl/parser_impl_test.cc
@@ -15,8 +15,8 @@
 #include "src/reader/wgsl/parser_impl.h"
 
 #include "gtest/gtest.h"
-#include "src/type/i32_type.h"
 #include "src/reader/wgsl/parser_impl_test_helper.h"
+#include "src/type/i32_type.h"
 
 namespace tint {
 namespace reader {
@@ -40,7 +40,7 @@
   ASSERT_TRUE(p->Parse()) << p->error();
 
   auto& m = p->get_module();
-  ASSERT_EQ(1u, m.functions().size());
+  ASSERT_EQ(1u, m.Functions().size());
   ASSERT_EQ(1u, m.global_variables().size());
 }
 
diff --git a/src/reader/wgsl/parser_test.cc b/src/reader/wgsl/parser_test.cc
index 1bb967e..c4b2fe7 100644
--- a/src/reader/wgsl/parser_test.cc
+++ b/src/reader/wgsl/parser_test.cc
@@ -42,7 +42,7 @@
   ASSERT_TRUE(p.Parse()) << p.error();
 
   auto m = p.module();
-  ASSERT_EQ(1u, m.functions().size());
+  ASSERT_EQ(1u, m.Functions().size());
   ASSERT_EQ(1u, m.global_variables().size());
 }
 
diff --git a/src/transform/emit_vertex_point_size.cc b/src/transform/emit_vertex_point_size.cc
index dd2acf0..79dd09b 100644
--- a/src/transform/emit_vertex_point_size.cc
+++ b/src/transform/emit_vertex_point_size.cc
@@ -41,7 +41,7 @@
 Transform::Output EmitVertexPointSize::Run(ast::Module* in) {
   Output out;
 
-  if (!in->HasStage(ast::PipelineStage::kVertex)) {
+  if (!in->Functions().HasStage(ast::PipelineStage::kVertex)) {
     // If the module doesn't have any vertex stages, then there's nothing to do.
     out.module = in->Clone();
     return out;
diff --git a/src/transform/vertex_pulling.cc b/src/transform/vertex_pulling.cc
index 104e80a..8a17e7b 100644
--- a/src/transform/vertex_pulling.cc
+++ b/src/transform/vertex_pulling.cc
@@ -85,8 +85,8 @@
   }
 
   // Find entry point
-  auto* func = in->FindFunctionBySymbolAndStage(
-      in->GetSymbol(cfg.entry_point_name), ast::PipelineStage::kVertex);
+  auto* func = in->Functions().Find(in->GetSymbol(cfg.entry_point_name),
+                                    ast::PipelineStage::kVertex);
   if (func == nullptr) {
     diag::Diagnostic err;
     err.severity = diag::Severity::Error;
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index cf30907..67875b5 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -115,13 +115,13 @@
     }
   }
 
-  if (!DetermineFunctions(mod_->functions())) {
+  if (!DetermineFunctions(mod_->Functions())) {
     return false;
   }
 
   // Walk over the caller to callee information and update functions with which
   // entry points call those functions.
-  for (auto* func : mod_->functions()) {
+  for (auto* func : mod_->Functions()) {
     if (!func->IsEntryPoint()) {
       continue;
     }
@@ -393,7 +393,7 @@
         caller_to_callee_[current_function_->symbol()].push_back(
             ident->symbol());
 
-        auto* callee_func = mod_->FindFunctionBySymbol(ident->symbol());
+        auto* callee_func = mod_->Functions().Find(ident->symbol());
         if (callee_func == nullptr) {
           set_error(expr->source(), "unable to find called function: " +
                                         mod_->SymbolToName(ident->symbol()));
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 4637ce7..5138838 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -292,7 +292,7 @@
   ast::VariableList params;
   auto* func = Func("my_func", params, ty.f32, ast::StatementList{},
                     ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   // Register the function
   EXPECT_TRUE(td()->Determine());
@@ -319,14 +319,14 @@
                              create<ast::ReturnStatement>(),
                          },
                          ast::FunctionDecorationList{});
-  mod->AddFunction(func_main);
+  mod->Functions().Add(func_main);
 
   auto* func = Func("func", params0, ty.f32,
                     ast::StatementList{
                         create<ast::ReturnStatement>(),
                     },
                     ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_FALSE(td()->Determine()) << td()->error();
   EXPECT_EQ(td()->error(),
@@ -471,7 +471,7 @@
   ast::VariableList params;
   auto* func = Func("my_func", params, ty.f32, ast::StatementList{},
                     ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   // Register the function
   EXPECT_TRUE(td()->Determine());
@@ -486,7 +486,7 @@
   ast::VariableList params;
   auto* func = Func("my_func", params, ty.f32, ast::StatementList{},
                     ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   // Register the function
   EXPECT_TRUE(td()->Determine());
@@ -624,7 +624,7 @@
 TEST_F(TypeDeterminerTest, Expr_Identifier_Function) {
   auto* func = Func("my_func", ast::VariableList{}, ty.f32,
                     ast::StatementList{}, ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   // Register the function
   EXPECT_TRUE(td()->Determine());
@@ -663,7 +663,7 @@
       },
       ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   // Register the function
   EXPECT_TRUE(td()->Determine());
@@ -700,7 +700,7 @@
       },
       ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   auto* func2 = Func(
       "func", ast::VariableList{}, ty.f32,
@@ -709,7 +709,7 @@
       },
       ast::FunctionDecorationList{});
 
-  mod->AddFunction(func2);
+  mod->Functions().Add(func2);
 
   // Register the function
   EXPECT_TRUE(td()->Determine());
@@ -734,7 +734,7 @@
            },
            ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   auto* v = Var("var", ast::StorageClass::kFunction, ty.f32);
   td()->RegisterVariableForTesting(v);
@@ -1587,7 +1587,7 @@
   auto* func = Func("func", ast::VariableList{}, ty.i32,
                     ast::StatementList{stmt}, ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
   EXPECT_EQ(var->storage_class(), ast::StorageClass::kFunction);
@@ -1599,7 +1599,7 @@
   auto* func = Func("func", ast::VariableList{}, ty.i32,
                     ast::StatementList{stmt}, ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
   EXPECT_EQ(var->storage_class(), ast::StorageClass::kNone);
@@ -1612,7 +1612,7 @@
   auto* func = Func("func", ast::VariableList{}, ty.i32,
                     ast::StatementList{stmt}, ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_FALSE(td()->Determine());
   EXPECT_EQ(td()->error(),
@@ -2758,11 +2758,11 @@
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
 
-  mod->AddFunction(func_b);
-  mod->AddFunction(func_c);
-  mod->AddFunction(func_a);
-  mod->AddFunction(ep_1);
-  mod->AddFunction(ep_2);
+  mod->Functions().Add(func_b);
+  mod->Functions().Add(func_c);
+  mod->Functions().Add(func_a);
+  mod->Functions().Add(ep_1);
+  mod->Functions().Add(ep_2);
 
   mod->AddGlobalVariable(Var("first", ast::StorageClass::kPrivate, ty.f32));
   mod->AddGlobalVariable(Var("second", ast::StorageClass::kPrivate, ty.f32));
diff --git a/src/validator/validator_function_test.cc b/src/validator/validator_function_test.cc
index 1ca339f..73c3ce2 100644
--- a/src/validator/validator_function_test.cc
+++ b/src/validator/validator_function_test.cc
@@ -49,7 +49,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
@@ -68,7 +68,7 @@
            ast::FunctionDecorationList{
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
@@ -89,7 +89,7 @@
                         create<ast::VariableDeclStatement>(var),
                     },
                     ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
@@ -105,7 +105,7 @@
   auto* func =
       Func(Source{Source::Location{12, 34}}, "func", ast::VariableList{},
            ty.i32, ast::StatementList{}, ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
@@ -127,13 +127,13 @@
            ast::FunctionDecorationList{
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
-  EXPECT_TRUE(td()->DetermineFunctions(mod->functions())) << td()->error();
+  EXPECT_TRUE(td()->DetermineFunctions(mod->Functions())) << td()->error();
 
   ValidatorImpl& v = Build();
 
-  EXPECT_TRUE(v.ValidateFunctions(mod->functions())) << v.error();
+  EXPECT_TRUE(v.ValidateFunctions(mod->Functions())) << v.error();
 }
 
 TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_fail) {
@@ -144,7 +144,7 @@
                             Source{Source::Location{12, 34}}, Expr(2)),
                     },
                     ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
@@ -165,7 +165,7 @@
                             Source{Source::Location{12, 34}}, Expr(2)),
                     },
                     ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
@@ -194,8 +194,8 @@
                          },
                          ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
-  mod->AddFunction(func_copy);
+  mod->Functions().Add(func);
+  mod->Functions().Add(func_copy);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
@@ -217,7 +217,7 @@
                          create<ast::ReturnStatement>(),
                      },
                      ast::FunctionDecorationList{});
-  mod->AddFunction(func0);
+  mod->Functions().Add(func0);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
@@ -241,7 +241,7 @@
                          create<ast::ReturnStatement>(Expr(2)),
                      },
                      ast::FunctionDecorationList{});
-  mod->AddFunction(func0);
+  mod->Functions().Add(func0);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
@@ -263,7 +263,7 @@
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
   ValidatorImpl& v = Build();
@@ -288,7 +288,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
   ValidatorImpl& v = Build();
@@ -313,7 +313,7 @@
           create<ast::StageDecoration>(ast::PipelineStage::kFragment),
       });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
   ValidatorImpl& v = Build();
@@ -335,7 +335,7 @@
            ast::FunctionDecorationList{
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
@@ -351,7 +351,7 @@
                         create<ast::ReturnStatement>(),
                     },
                     ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
diff --git a/src/validator/validator_impl.cc b/src/validator/validator_impl.cc
index c673040..46831e9 100644
--- a/src/validator/validator_impl.cc
+++ b/src/validator/validator_impl.cc
@@ -71,10 +71,10 @@
   if (!ValidateConstructedTypes(module_.constructed_types())) {
     return false;
   }
-  if (!ValidateFunctions(module_.functions())) {
+  if (!ValidateFunctions(module_.Functions())) {
     return false;
   }
-  if (!ValidateEntryPoint(module_.functions())) {
+  if (!ValidateEntryPoint(module_.Functions())) {
     return false;
   }
   function_stack_.pop_scope();
diff --git a/src/validator/validator_test.cc b/src/validator/validator_test.cc
index a4a03d1..9ab31eb 100644
--- a/src/validator/validator_test.cc
+++ b/src/validator/validator_test.cc
@@ -392,7 +392,7 @@
                             Source{Source::Location{12, 34}}, lhs, rhs),
                     },
                     ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ValidatorImpl& v = Build();
 
@@ -420,7 +420,7 @@
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
@@ -578,7 +578,7 @@
                     },
                     ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
   EXPECT_TRUE(td()->DetermineFunction(func)) << td()->error();
@@ -608,7 +608,7 @@
                     },
                     ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
   EXPECT_TRUE(td()->DetermineFunction(func)) << td()->error();
@@ -707,8 +707,8 @@
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
 
-  mod->AddFunction(func0);
-  mod->AddFunction(func1);
+  mod->Functions().Add(func0);
+  mod->Functions().Add(func1);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
diff --git a/src/validator/validator_type_test.cc b/src/validator/validator_type_test.cc
index b43078c..30dcad6 100644
--- a/src/validator/validator_type_test.cc
+++ b/src/validator/validator_type_test.cc
@@ -172,7 +172,7 @@
            ast::FunctionDecorationList{
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
@@ -197,7 +197,7 @@
                         create<ast::ReturnStatement>(),
                     },
                     ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   auto* main =
       Func("main", ast::VariableList{}, ty.void_,
@@ -207,7 +207,7 @@
            ast::FunctionDecorationList{
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
-  mod->AddFunction(main);
+  mod->Functions().Add(main);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
 
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index c30a220..93ab2e6 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -160,7 +160,7 @@
 
   std::unordered_set<Symbol> emitted_globals;
   // Make sure all entry point data is emitted before the entry point functions
-  for (auto* func : module_->functions()) {
+  for (auto* func : module_->Functions()) {
     if (!func->IsEntryPoint()) {
       continue;
     }
@@ -170,13 +170,13 @@
     }
   }
 
-  for (auto* func : module_->functions()) {
+  for (auto* func : module_->Functions()) {
     if (!EmitFunction(out, func)) {
       return false;
     }
   }
 
-  for (auto* func : module_->functions()) {
+  for (auto* func : module_->Functions()) {
     if (!func->IsEntryPoint()) {
       continue;
     }
@@ -631,7 +631,7 @@
     name = it->second;
   }
 
-  auto* func = module_->FindFunctionBySymbol(ident->symbol());
+  auto* func = module_->Functions().Find(ident->symbol());
   if (func == nullptr) {
     error_ =
         "Unable to find function: " + module_->SymbolToName(ident->symbol());
diff --git a/src/writer/hlsl/generator_impl_binary_test.cc b/src/writer/hlsl/generator_impl_binary_test.cc
index 1786684..704cb5a 100644
--- a/src/writer/hlsl/generator_impl_binary_test.cc
+++ b/src/writer/hlsl/generator_impl_binary_test.cc
@@ -507,7 +507,7 @@
 
   auto* func = Func("foo", ast::VariableList{}, ty.void_, ast::StatementList{},
                     ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ast::ExpressionList params;
   params.push_back(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
diff --git a/src/writer/hlsl/generator_impl_call_test.cc b/src/writer/hlsl/generator_impl_call_test.cc
index 23b2176..5b3a25c 100644
--- a/src/writer/hlsl/generator_impl_call_test.cc
+++ b/src/writer/hlsl/generator_impl_call_test.cc
@@ -34,7 +34,7 @@
 
   auto* func = Func("my_func", ast::VariableList{}, ty.void_,
                     ast::StatementList{}, ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -47,7 +47,7 @@
 
   auto* func = Func("my_func", ast::VariableList{}, ty.void_,
                     ast::StatementList{}, ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -60,7 +60,7 @@
 
   auto* func = Func("my_func", ast::VariableList{}, ty.void_,
                     ast::StatementList{}, ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/hlsl/generator_impl_function_entry_point_data_test.cc b/src/writer/hlsl/generator_impl_function_entry_point_data_test.cc
index 3f4e9ee..e29725fe 100644
--- a/src/writer/hlsl/generator_impl_function_entry_point_data_test.cc
+++ b/src/writer/hlsl/generator_impl_function_entry_point_data_test.cc
@@ -70,7 +70,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   std::unordered_set<Symbol> globals;
 
@@ -123,7 +123,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   std::unordered_set<Symbol> globals;
 
@@ -176,7 +176,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   std::unordered_set<Symbol> globals;
 
@@ -229,7 +229,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   std::unordered_set<Symbol> globals;
 
@@ -279,7 +279,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kCompute),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   std::unordered_set<Symbol> globals;
 
@@ -324,7 +324,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kCompute),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   std::unordered_set<Symbol> globals;
 
@@ -377,7 +377,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   std::unordered_set<Symbol> globals;
 
diff --git a/src/writer/hlsl/generator_impl_function_test.cc b/src/writer/hlsl/generator_impl_function_test.cc
index e5a8570..d799d0f 100644
--- a/src/writer/hlsl/generator_impl_function_test.cc
+++ b/src/writer/hlsl/generator_impl_function_test.cc
@@ -59,7 +59,7 @@
                     },
                     ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -80,7 +80,7 @@
                     },
                     ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -105,7 +105,7 @@
            },
            ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -128,7 +128,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -169,7 +169,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -221,7 +221,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -276,7 +276,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -325,7 +325,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -378,7 +378,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -431,7 +431,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -481,7 +481,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -528,7 +528,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -582,7 +582,7 @@
       },
       ast::FunctionDecorationList{});
 
-  mod->AddFunction(sub_func);
+  mod->Functions().Add(sub_func);
 
   auto* func_1 = Func(
       "ep_1", ast::VariableList{}, ty.void_,
@@ -594,7 +594,7 @@
           create<ast::StageDecoration>(ast::PipelineStage::kFragment),
       });
 
-  mod->AddFunction(func_1);
+  mod->Functions().Add(func_1);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -646,7 +646,7 @@
       },
       ast::FunctionDecorationList{});
 
-  mod->AddFunction(sub_func);
+  mod->Functions().Add(sub_func);
 
   auto* func_1 =
       Func("ep_1", ast::VariableList{}, ty.void_,
@@ -659,7 +659,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func_1);
+  mod->Functions().Add(func_1);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -715,7 +715,7 @@
       },
       ast::FunctionDecorationList{});
 
-  mod->AddFunction(sub_func);
+  mod->Functions().Add(sub_func);
 
   auto* func_1 =
       Func("ep_1", ast::VariableList{}, ty.void_,
@@ -728,7 +728,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func_1);
+  mod->Functions().Add(func_1);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -779,7 +779,7 @@
       },
       ast::FunctionDecorationList{});
 
-  mod->AddFunction(sub_func);
+  mod->Functions().Add(sub_func);
 
   auto* var = Var("v", ast::StorageClass::kFunction, ty.f32,
                   Call("sub_func", 1.0f), ast::VariableDecorationList{});
@@ -794,7 +794,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -839,7 +839,7 @@
       },
       ast::FunctionDecorationList{});
 
-  mod->AddFunction(sub_func);
+  mod->Functions().Add(sub_func);
 
   auto* var = Var("v", ast::StorageClass::kFunction, ty.f32,
                   Call("sub_func", 1.0f), ast::VariableDecorationList{});
@@ -854,7 +854,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -902,7 +902,7 @@
           create<ast::StageDecoration>(ast::PipelineStage::kFragment),
       });
 
-  mod->AddFunction(func_1);
+  mod->Functions().Add(func_1);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -933,7 +933,7 @@
           create<ast::StageDecoration>(ast::PipelineStage::kFragment),
       });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -956,7 +956,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kCompute),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -983,7 +983,7 @@
                create<ast::WorkgroupDecoration>(2u, 4u, 6u),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -1008,7 +1008,7 @@
       },
       ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -1071,7 +1071,7 @@
                  create<ast::StageDecoration>(ast::PipelineStage::kCompute),
              });
 
-    mod->AddFunction(func);
+    mod->Functions().Add(func);
   }
 
   {
@@ -1088,7 +1088,7 @@
                  create<ast::StageDecoration>(ast::PipelineStage::kCompute),
              });
 
-    mod->AddFunction(func);
+    mod->Functions().Add(func);
   }
 
   ASSERT_TRUE(td.Determine()) << td.error();
diff --git a/src/writer/hlsl/generator_impl_test.cc b/src/writer/hlsl/generator_impl_test.cc
index a4f4ffc..a42c4b9 100644
--- a/src/writer/hlsl/generator_impl_test.cc
+++ b/src/writer/hlsl/generator_impl_test.cc
@@ -30,7 +30,7 @@
 TEST_F(HlslGeneratorImplTest, Generate) {
   auto* func = Func("my_func", ast::VariableList{}, ty.void_,
                     ast::StatementList{}, ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 254ca89..b0be9aa 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -138,7 +138,7 @@
   }
 
   // Make sure all entry point data is emitted before the entry point functions
-  for (auto* func : module_->functions()) {
+  for (auto* func : module_->Functions()) {
     if (!func->IsEntryPoint()) {
       continue;
     }
@@ -148,13 +148,13 @@
     }
   }
 
-  for (auto* func : module_->functions()) {
+  for (auto* func : module_->Functions()) {
     if (!EmitFunction(func)) {
       return false;
     }
   }
 
-  for (auto* func : module_->functions()) {
+  for (auto* func : module_->Functions()) {
     if (!func->IsEntryPoint()) {
       continue;
     }
@@ -525,7 +525,7 @@
     name = it->second;
   }
 
-  auto* func = module_->FindFunctionBySymbol(ident->symbol());
+  auto* func = module_->Functions().Find(ident->symbol());
   if (func == nullptr) {
     error_ =
         "Unable to find function: " + module_->SymbolToName(ident->symbol());
diff --git a/src/writer/msl/generator_impl_call_test.cc b/src/writer/msl/generator_impl_call_test.cc
index 44159f8..679bfb0 100644
--- a/src/writer/msl/generator_impl_call_test.cc
+++ b/src/writer/msl/generator_impl_call_test.cc
@@ -35,7 +35,7 @@
   auto* call = Call("my_func");
   auto* func = Func("my_func", ast::VariableList{}, ty.void_,
                     ast::StatementList{}, ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -47,7 +47,7 @@
   auto* call = Call("my_func", "param1", "param2");
   auto* func = Func("my_func", ast::VariableList{}, ty.void_,
                     ast::StatementList{}, ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -59,7 +59,7 @@
   auto* call = Call("my_func", "param1", "param2");
   auto* func = Func("my_func", ast::VariableList{}, ty.void_,
                     ast::StatementList{}, ast::FunctionDecorationList{});
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   auto* expr = create<ast::CallStatement>(call);
 
diff --git a/src/writer/msl/generator_impl_function_entry_point_data_test.cc b/src/writer/msl/generator_impl_function_entry_point_data_test.cc
index 8271f72..00298f6 100644
--- a/src/writer/msl/generator_impl_function_entry_point_data_test.cc
+++ b/src/writer/msl/generator_impl_function_entry_point_data_test.cc
@@ -71,7 +71,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -119,7 +119,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kVertex),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -167,7 +167,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -215,7 +215,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -260,7 +260,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kCompute),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -300,7 +300,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kCompute),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -345,7 +345,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
diff --git a/src/writer/msl/generator_impl_function_test.cc b/src/writer/msl/generator_impl_function_test.cc
index 80aefa2..0bec2fb 100644
--- a/src/writer/msl/generator_impl_function_test.cc
+++ b/src/writer/msl/generator_impl_function_test.cc
@@ -62,7 +62,7 @@
                     },
                     ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -85,7 +85,7 @@
                     },
                     ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -112,7 +112,7 @@
                     },
                     ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -134,7 +134,7 @@
                     ast::FunctionDecorationList{create<ast::StageDecoration>(
                         ast::PipelineStage::kFragment)});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -174,7 +174,7 @@
            ast::FunctionDecorationList{
                create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -223,7 +223,7 @@
                     ast::FunctionDecorationList{create<ast::StageDecoration>(
                         ast::PipelineStage::kFragment)});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -278,7 +278,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -323,7 +323,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -374,7 +374,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -428,7 +428,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -483,7 +483,7 @@
   auto* sub_func =
       Func("sub_func", params, ty.f32, body, ast::FunctionDecorationList{});
 
-  mod->AddFunction(sub_func);
+  mod->Functions().Add(sub_func);
 
   body = ast::StatementList{
       create<ast::AssignmentStatement>(Expr("bar"), Call("sub_func", 1.0f)),
@@ -495,7 +495,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func_1);
+  mod->Functions().Add(func_1);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -547,7 +547,7 @@
                         },
                         ast::FunctionDecorationList{});
 
-  mod->AddFunction(sub_func);
+  mod->Functions().Add(sub_func);
 
   auto body = ast::StatementList{
       create<ast::AssignmentStatement>(Expr("depth"), Call("sub_func", 1.0f)),
@@ -560,7 +560,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func_1);
+  mod->Functions().Add(func_1);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -616,7 +616,7 @@
   auto* sub_func =
       Func("sub_func", params, ty.f32, body, ast::FunctionDecorationList{});
 
-  mod->AddFunction(sub_func);
+  mod->Functions().Add(sub_func);
 
   body = ast::StatementList{
       create<ast::AssignmentStatement>(Expr("depth"), Call("sub_func", 1.0f)),
@@ -628,7 +628,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func_1);
+  mod->Functions().Add(func_1);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -674,7 +674,7 @@
   auto* sub_func =
       Func("sub_func", params, ty.f32, body, ast::FunctionDecorationList{});
 
-  mod->AddFunction(sub_func);
+  mod->Functions().Add(sub_func);
 
   ast::ExpressionList expr;
   expr.push_back(Expr(1.0f));
@@ -692,7 +692,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -741,7 +741,7 @@
   auto* sub_func =
       Func("sub_func", params, ty.f32, body, ast::FunctionDecorationList{});
 
-  mod->AddFunction(sub_func);
+  mod->Functions().Add(sub_func);
 
   auto* var = Var("v", ast::StorageClass::kFunction, ty.f32,
                   Call("sub_func", 1.0f), ast::VariableDecorationList{});
@@ -756,7 +756,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -810,7 +810,7 @@
   auto* sub_func =
       Func("sub_func", params, ty.f32, body, ast::FunctionDecorationList{});
 
-  mod->AddFunction(sub_func);
+  mod->Functions().Add(sub_func);
 
   ast::ExpressionList expr;
   expr.push_back(Expr(1.0f));
@@ -828,7 +828,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -881,7 +881,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(func_1);
+  mod->Functions().Add(func_1);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
@@ -914,7 +914,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kCompute),
            });
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -938,7 +938,7 @@
                     },
                     ast::FunctionDecorationList{});
 
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
@@ -1004,7 +1004,7 @@
                  create<ast::StageDecoration>(ast::PipelineStage::kCompute),
              });
 
-    mod->AddFunction(func);
+    mod->Functions().Add(func);
   }
 
   {
@@ -1018,7 +1018,7 @@
              ast::FunctionDecorationList{
                  create<ast::StageDecoration>(ast::PipelineStage::kCompute)});
 
-    mod->AddFunction(func);
+    mod->Functions().Add(func);
   }
 
   ASSERT_TRUE(td.Determine()) << td.error();
diff --git a/src/writer/msl/generator_impl_test.cc b/src/writer/msl/generator_impl_test.cc
index 42c1514..183c08d 100644
--- a/src/writer/msl/generator_impl_test.cc
+++ b/src/writer/msl/generator_impl_test.cc
@@ -53,7 +53,7 @@
            ast::FunctionDecorationList{
                create<ast::StageDecoration>(ast::PipelineStage::kCompute),
            });
-  mod->AddFunction(func);
+  mod->Functions().Add(func);
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index bfd42d7..d79f622 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -302,7 +302,7 @@
     }
   }
 
-  for (auto* func : mod_->functions()) {
+  for (auto* func : mod_->Functions()) {
     if (!GenerateFunction(func)) {
       return false;
     }
diff --git a/src/writer/spirv/builder_function_test.cc b/src/writer/spirv/builder_function_test.cc
index 3796661..58b13b3 100644
--- a/src/writer/spirv/builder_function_test.cc
+++ b/src/writer/spirv/builder_function_test.cc
@@ -261,7 +261,7 @@
                  create<ast::StageDecoration>(ast::PipelineStage::kCompute),
              });
 
-    mod->AddFunction(func);
+    mod->Functions().Add(func);
   }
 
   {
@@ -278,7 +278,7 @@
                  create<ast::StageDecoration>(ast::PipelineStage::kCompute),
              });
 
-    mod->AddFunction(func);
+    mod->Functions().Add(func);
   }
 
   ASSERT_TRUE(td.Determine()) << td.error();
diff --git a/src/writer/spirv/builder_intrinsic_texture_test.cc b/src/writer/spirv/builder_intrinsic_texture_test.cc
index f6bbad2..7afa09e 100644
--- a/src/writer/spirv/builder_intrinsic_texture_test.cc
+++ b/src/writer/spirv/builder_intrinsic_texture_test.cc
@@ -4165,7 +4165,7 @@
                create<ast::StageDecoration>(ast::PipelineStage::kFragment),
            });
 
-  mod->AddFunction(main);
+  mod->Functions().Add(main);
 
   ASSERT_TRUE(td.Determine()) << td.error();
 
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index c395c60..520a595 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -101,7 +101,7 @@
     out_ << std::endl;
   }
 
-  for (auto* func : module_.functions()) {
+  for (auto* func : module_.Functions()) {
     if (!EmitFunction(func)) {
       return false;
     }
@@ -113,8 +113,7 @@
 
 bool GeneratorImpl::GenerateEntryPoint(ast::PipelineStage stage,
                                        const std::string& name) {
-  auto* func =
-      module_.FindFunctionBySymbolAndStage(module_.GetSymbol(name), stage);
+  auto* func = module_.Functions().Find(module_.GetSymbol(name), stage);
   if (func == nullptr) {
     error_ = "Unable to find requested entry point: " + name;
     return false;
@@ -153,7 +152,7 @@
     out_ << std::endl;
   }
 
-  for (auto* f : module_.functions()) {
+  for (auto* f : module_.Functions()) {
     if (!f->HasAncestorEntryPoint(module_.GetSymbol(name))) {
       continue;
     }
diff --git a/src/writer/wgsl/generator_impl_function_test.cc b/src/writer/wgsl/generator_impl_function_test.cc
index 9fbca86..0176f7b 100644
--- a/src/writer/wgsl/generator_impl_function_test.cc
+++ b/src/writer/wgsl/generator_impl_function_test.cc
@@ -212,7 +212,7 @@
                  create<ast::StageDecoration>(ast::PipelineStage::kCompute),
              });
 
-    mod->AddFunction(func);
+    mod->Functions().Add(func);
   }
 
   {
@@ -231,7 +231,7 @@
                  create<ast::StageDecoration>(ast::PipelineStage::kCompute),
              });
 
-    mod->AddFunction(func);
+    mod->Functions().Add(func);
   }
 
   ASSERT_TRUE(td.Determine()) << td.error();
diff --git a/src/writer/wgsl/generator_impl_test.cc b/src/writer/wgsl/generator_impl_test.cc
index 31312fa..bf88db1 100644
--- a/src/writer/wgsl/generator_impl_test.cc
+++ b/src/writer/wgsl/generator_impl_test.cc
@@ -30,8 +30,9 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Generate) {
-  mod->AddFunction(Func("my_func", ast::VariableList{}, ty.void_,
-                        ast::StatementList{}, ast::FunctionDecorationList{}));
+  mod->Functions().Add(Func("my_func", ast::VariableList{}, ty.void_,
+                            ast::StatementList{},
+                            ast::FunctionDecorationList{}));
 
   GeneratorImpl& gen = Build();