[inspector] Update tests to use WGSL.

This CL updates the inspector tests which currently use the builder
methods to instead pass in WGSL directly. This is a lot easier to read
and understand what is under test.

Bug: 401977519
Change-Id: I1c9d0cd8c8429b4274108bdedac94ac0c8af2850
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/234154
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Auto-Submit: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/wgsl/inspector/BUILD.bazel b/src/tint/lang/wgsl/inspector/BUILD.bazel
index 5f342f3..4879cea 100644
--- a/src/tint/lang/wgsl/inspector/BUILD.bazel
+++ b/src/tint/lang/wgsl/inspector/BUILD.bazel
@@ -79,8 +79,6 @@
   name = "test",
   alwayslink = True,
   srcs = [
-    "inspector_builder_test.cc",
-    "inspector_builder_test.h",
     "inspector_test.cc",
   ],
   deps = [
@@ -95,7 +93,6 @@
     "//src/tint/lang/wgsl/features",
     "//src/tint/lang/wgsl/inspector",
     "//src/tint/lang/wgsl/program",
-    "//src/tint/lang/wgsl/resolver",
     "//src/tint/lang/wgsl/sem",
     "//src/tint/utils",
     "//src/tint/utils/containers",
diff --git a/src/tint/lang/wgsl/inspector/BUILD.cmake b/src/tint/lang/wgsl/inspector/BUILD.cmake
index 3bc95a3..e0f256d 100644
--- a/src/tint/lang/wgsl/inspector/BUILD.cmake
+++ b/src/tint/lang/wgsl/inspector/BUILD.cmake
@@ -82,8 +82,6 @@
 # Condition: TINT_BUILD_WGSL_READER
 ################################################################################
 tint_add_target(tint_lang_wgsl_inspector_test test
-  lang/wgsl/inspector/inspector_builder_test.cc
-  lang/wgsl/inspector/inspector_builder_test.h
   lang/wgsl/inspector/inspector_test.cc
 )
 
@@ -99,7 +97,6 @@
   tint_lang_wgsl_features
   tint_lang_wgsl_inspector
   tint_lang_wgsl_program
-  tint_lang_wgsl_resolver
   tint_lang_wgsl_sem
   tint_utils
   tint_utils_containers
diff --git a/src/tint/lang/wgsl/inspector/BUILD.gn b/src/tint/lang/wgsl/inspector/BUILD.gn
index 785b622..080e22f 100644
--- a/src/tint/lang/wgsl/inspector/BUILD.gn
+++ b/src/tint/lang/wgsl/inspector/BUILD.gn
@@ -80,11 +80,7 @@
 if (tint_build_unittests) {
   if (tint_build_wgsl_reader) {
     tint_unittests_source_set("unittests") {
-      sources = [
-        "inspector_builder_test.cc",
-        "inspector_builder_test.h",
-        "inspector_test.cc",
-      ]
+      sources = [ "inspector_test.cc" ]
       deps = [
         "${dawn_root}/src/utils:utils",
         "${tint_src_dir}:gmock_and_gtest",
@@ -99,7 +95,6 @@
         "${tint_src_dir}/lang/wgsl/features",
         "${tint_src_dir}/lang/wgsl/inspector",
         "${tint_src_dir}/lang/wgsl/program",
-        "${tint_src_dir}/lang/wgsl/resolver",
         "${tint_src_dir}/lang/wgsl/sem",
         "${tint_src_dir}/utils",
         "${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/wgsl/inspector/inspector_builder_test.cc b/src/tint/lang/wgsl/inspector/inspector_builder_test.cc
deleted file mode 100644
index 0def33d..0000000
--- a/src/tint/lang/wgsl/inspector/inspector_builder_test.cc
+++ /dev/null
@@ -1,396 +0,0 @@
-// Copyright 2021 The Dawn & Tint Authors
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-//    list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-//    this list of conditions and the following disclaimer in the documentation
-//    and/or other materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its
-//    contributors may be used to endorse or promote products derived from
-//    this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "src/tint/lang/wgsl/inspector/inspector_builder_test.h"
-
-#include <memory>
-#include <string>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "src/tint/lang/core/fluent_types.h"
-#include "src/tint/lang/wgsl/reader/reader.h"
-#include "src/tint/lang/wgsl/resolver/resolve.h"
-
-using namespace tint::core::fluent_types;  // NOLINT
-
-namespace tint::inspector {
-
-InspectorBuilder::InspectorBuilder() = default;
-InspectorBuilder::~InspectorBuilder() = default;
-
-void InspectorBuilder::MakeEmptyBodyFunction(std::string name,
-                                             VectorRef<const ast::Attribute*> attributes) {
-    Func(name, tint::Empty, ty.void_(), Vector{Return()}, attributes);
-}
-
-void InspectorBuilder::MakeCallerBodyFunction(std::string caller,
-                                              VectorRef<std::string> callees,
-                                              VectorRef<const ast::Attribute*> attributes) {
-    Vector<const ast::Statement*, 8> body;
-    body.Reserve(callees.Length() + 1);
-    for (auto callee : callees) {
-        body.Push(CallStmt(Call(callee)));
-    }
-    body.Push(Return());
-
-    Func(caller, tint::Empty, ty.void_(), body, attributes);
-}
-
-const ast::Struct* InspectorBuilder::MakeInOutStruct(std::string name,
-                                                     VectorRef<InOutInfo> inout_vars) {
-    Vector<const ast::StructMember*, 8> members;
-    for (auto var : inout_vars) {
-        std::string member_name;
-        uint32_t location;
-        std::tie(member_name, location) = var;
-        members.Push(Member(member_name, ty.u32(),
-                            Vector{
-                                Location(AInt(location)),
-                                Flat(),
-                            }));
-    }
-    return Structure(name, members);
-}
-
-const ast::Function* InspectorBuilder::MakePlainGlobalReferenceBodyFunction(
-    std::string func,
-    std::string var,
-    ast::Type type,
-    VectorRef<const ast::Attribute*> attributes) {
-    Vector<const ast::Statement*, 3> stmts;
-    stmts.Push(Decl(Var("local_" + var, type)));
-    stmts.Push(Assign("local_" + var, var));
-    stmts.Push(Return());
-    return Func(func, tint::Empty, ty.void_(), std::move(stmts), std::move(attributes));
-}
-
-bool InspectorBuilder::ContainsName(VectorRef<StageVariable> vec, const std::string& name) {
-    for (auto& s : vec) {
-        if (s.name == name) {
-            return true;
-        }
-    }
-    return false;
-}
-
-std::string InspectorBuilder::StructMemberName(size_t idx, ast::Type type) {
-    return std::to_string(idx) + type->identifier->symbol.Name();
-}
-
-const ast::Struct* InspectorBuilder::MakeStructType(const std::string& name,
-                                                    VectorRef<ast::Type> member_types) {
-    Vector<const ast::StructMember*, 8> members;
-    for (auto type : member_types) {
-        members.Push(MakeStructMember(members.Length(), type, {}));
-    }
-    return MakeStructTypeFromMembers(name, std::move(members));
-}
-
-const ast::Struct* InspectorBuilder::MakeStructTypeFromMembers(
-    const std::string& name,
-    VectorRef<const ast::StructMember*> members) {
-    return Structure(name, std::move(members));
-}
-
-const ast::StructMember* InspectorBuilder::MakeStructMember(
-    size_t index,
-    ast::Type type,
-    VectorRef<const ast::Attribute*> attributes) {
-    return Member(StructMemberName(index, type), type, std::move(attributes));
-}
-
-const ast::Struct* InspectorBuilder::MakeUniformBufferType(const std::string& name,
-                                                           VectorRef<ast::Type> member_types) {
-    return MakeStructType(name, member_types);
-}
-
-std::function<ast::Type()> InspectorBuilder::MakeStorageBufferTypes(
-    const std::string& name,
-    VectorRef<ast::Type> member_types) {
-    MakeStructType(name, member_types);
-    return [this, name] { return ty(name); };
-}
-
-void InspectorBuilder::AddUniformBuffer(const std::string& name,
-                                        ast::Type type,
-                                        uint32_t group,
-                                        uint32_t binding) {
-    GlobalVar(name, type, core::AddressSpace::kUniform, Binding(AInt(binding)), Group(AInt(group)));
-}
-
-void InspectorBuilder::AddWorkgroupStorage(const std::string& name, ast::Type type) {
-    GlobalVar(name, type, core::AddressSpace::kWorkgroup);
-}
-
-void InspectorBuilder::AddStorageBuffer(const std::string& name,
-                                        ast::Type type,
-                                        core::Access access,
-                                        uint32_t group,
-                                        uint32_t binding) {
-    GlobalVar(name, type, core::AddressSpace::kStorage, access, Binding(AInt(binding)),
-              Group(AInt(group)));
-}
-
-void InspectorBuilder::MakeStructVariableReferenceBodyFunction(
-    std::string func_name,
-    std::string struct_name,
-    VectorRef<std::tuple<size_t, ast::Type>> members) {
-    Vector<const ast::Statement*, 8> stmts;
-    for (auto member : members) {
-        size_t member_idx;
-        ast::Type member_type;
-        std::tie(member_idx, member_type) = member;
-        std::string member_name = StructMemberName(member_idx, member_type);
-
-        stmts.Push(Decl(Var("local" + member_name, member_type)));
-    }
-
-    for (auto member : members) {
-        size_t member_idx;
-        ast::Type member_type;
-        std::tie(member_idx, member_type) = member;
-        std::string member_name = StructMemberName(member_idx, member_type);
-
-        stmts.Push(Assign("local" + member_name, MemberAccessor(struct_name, member_name)));
-    }
-
-    stmts.Push(Return());
-
-    Func(func_name, tint::Empty, ty.void_(), stmts);
-}
-
-void InspectorBuilder::AddSampler(const std::string& name, uint32_t group, uint32_t binding) {
-    GlobalVar(name, ty.sampler(core::type::SamplerKind::kSampler), Binding(AInt(binding)),
-              Group(AInt(group)));
-}
-
-void InspectorBuilder::AddComparisonSampler(const std::string& name,
-                                            uint32_t group,
-                                            uint32_t binding) {
-    GlobalVar(name, ty.sampler(core::type::SamplerKind::kComparisonSampler), Binding(AInt(binding)),
-              Group(AInt(group)));
-}
-
-void InspectorBuilder::AddResource(const std::string& name,
-                                   ast::Type type,
-                                   uint32_t group,
-                                   uint32_t binding) {
-    GlobalVar(name, type, Binding(AInt(binding)), Group(AInt(group)));
-}
-
-void InspectorBuilder::AddGlobalVariable(const std::string& name, ast::Type type) {
-    GlobalVar(name, type, core::AddressSpace::kPrivate);
-}
-
-const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
-    const std::string& func_name,
-    const std::string& texture_name,
-    const std::string& sampler_name,
-    const std::string& coords_name,
-    ast::Type base_type,
-    VectorRef<const ast::Attribute*> attributes) {
-    std::string result_name = "sampler_result";
-
-    Vector stmts{
-        Decl(Var(result_name, ty.vec(base_type, 4))),
-        Assign(result_name, Call("textureSample", texture_name, sampler_name, coords_name)),
-        Return(),
-    };
-    return Func(func_name, tint::Empty, ty.void_(), std::move(stmts), std::move(attributes));
-}
-
-const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
-    const std::string& func_name,
-    const std::string& texture_name,
-    const std::string& sampler_name,
-    const std::string& coords_name,
-    const std::string& array_index,
-    ast::Type base_type,
-    VectorRef<const ast::Attribute*> attributes) {
-    std::string result_name = "sampler_result";
-
-    Vector stmts{
-        Decl(Var("sampler_result", ty.vec(base_type, 4))),
-        Assign("sampler_result",
-               Call("textureSample", texture_name, sampler_name, coords_name, array_index)),
-        Return(),
-    };
-    return Func(func_name, tint::Empty, ty.void_(), std::move(stmts), std::move(attributes));
-}
-
-const ast::Function* InspectorBuilder::MakeComparisonSamplerReferenceBodyFunction(
-    const std::string& func_name,
-    const std::string& texture_name,
-    const std::string& sampler_name,
-    const std::string& coords_name,
-    const std::string& depth_name,
-    ast::Type base_type,
-    VectorRef<const ast::Attribute*> attributes) {
-    std::string result_name = "sampler_result";
-
-    Vector stmts{
-        Decl(Var("sampler_result", base_type)),
-        Assign("sampler_result",
-               Call("textureSampleCompare", texture_name, sampler_name, coords_name, depth_name)),
-        Return(),
-    };
-    return Func(func_name, tint::Empty, ty.void_(), std::move(stmts), std::move(attributes));
-}
-
-ast::Type InspectorBuilder::GetBaseType(ResourceBinding::SampledKind sampled_kind) {
-    switch (sampled_kind) {
-        case ResourceBinding::SampledKind::kFloat:
-            return ty.f32();
-        case ResourceBinding::SampledKind::kSInt:
-            return ty.i32();
-        case ResourceBinding::SampledKind::kUInt:
-            return ty.u32();
-        default:
-            return ast::Type{};
-    }
-}
-
-ast::Type InspectorBuilder::GetCoordsType(core::type::TextureDimension dim, ast::Type scalar) {
-    switch (dim) {
-        case core::type::TextureDimension::k1d:
-            return scalar;
-        case core::type::TextureDimension::k2d:
-        case core::type::TextureDimension::k2dArray:
-            return ty.vec2(scalar);
-        case core::type::TextureDimension::k3d:
-        case core::type::TextureDimension::kCube:
-        case core::type::TextureDimension::kCubeArray:
-            return ty.vec3(scalar);
-        default:
-            [=] {
-                StringStream str;
-                str << dim;
-                FAIL() << "Unsupported texture dimension: " << str.str();
-            }();
-    }
-    return ast::Type{};
-}
-
-ast::Type InspectorBuilder::MakeStorageTextureTypes(core::type::TextureDimension dim,
-                                                    core::TexelFormat format,
-                                                    core::Access access) {
-    return ty.storage_texture(dim, format, access);
-}
-
-void InspectorBuilder::AddStorageTexture(const std::string& name,
-                                         ast::Type type,
-                                         uint32_t group,
-                                         uint32_t binding) {
-    GlobalVar(name, type, Binding(AInt(binding)), Group(AInt(group)));
-}
-
-const ast::Function* InspectorBuilder::MakeStorageTextureBodyFunction(
-    const std::string& func_name,
-    const std::string& st_name,
-    ast::Type dim_type,
-    VectorRef<const ast::Attribute*> attributes) {
-    Vector stmts{
-        Decl(Var("dim", dim_type)),
-        Assign("dim", Call("textureDimensions", st_name)),
-        Return(),
-    };
-
-    return Func(func_name, tint::Empty, ty.void_(), std::move(stmts), std::move(attributes));
-}
-
-std::function<ast::Type()> InspectorBuilder::GetTypeFunction(ComponentType component,
-                                                             CompositionType composition) {
-    std::function<ast::Type()> func;
-    switch (component) {
-        case ComponentType::kF32:
-            func = [this] { return ty.f32(); };
-            break;
-        case ComponentType::kI32:
-            func = [this] { return ty.i32(); };
-            break;
-        case ComponentType::kU32:
-            func = [this] { return ty.u32(); };
-            break;
-        case ComponentType::kF16:
-            func = [this] { return ty.f16(); };
-            break;
-        case ComponentType::kUnknown:
-            return [] { return ast::Type{}; };
-    }
-
-    uint32_t n;
-    switch (composition) {
-        case CompositionType::kScalar:
-            return func;
-        case CompositionType::kVec2:
-            n = 2;
-            break;
-        case CompositionType::kVec3:
-            n = 3;
-            break;
-        case CompositionType::kVec4:
-            n = 4;
-            break;
-        default:
-            return [] { return ast::Type{}; };
-    }
-
-    return [this, func, n] { return ty.vec(func(), n); };
-}
-
-Inspector& InspectorBuilder::Initialize(std::string shader) {
-    if (inspector_) {
-        return *inspector_;
-    }
-
-    wgsl::reader::Options options;
-    options.allowed_features = wgsl::AllowedFeatures::Everything();
-    file_ = std::make_unique<Source::File>("test", shader);
-    program_ = std::make_unique<Program>(wgsl::reader::Parse(file_.get(), options));
-    if (!program_->IsValid()) {
-        ADD_FAILURE() << program_->Diagnostics();
-    }
-    inspector_ = std::make_unique<Inspector>(*program_);
-    return *inspector_;
-}
-
-Inspector& InspectorBuilder::Build() {
-    if (inspector_) {
-        return *inspector_;
-    }
-    program_ = std::make_unique<Program>(resolver::Resolve(*this));
-    if (!program_->IsValid()) {
-        ADD_FAILURE() << program_->Diagnostics();
-    }
-    inspector_ = std::make_unique<Inspector>(*program_);
-    return *inspector_;
-}
-
-}  // namespace tint::inspector
diff --git a/src/tint/lang/wgsl/inspector/inspector_builder_test.h b/src/tint/lang/wgsl/inspector/inspector_builder_test.h
deleted file mode 100644
index fb18cdb..0000000
--- a/src/tint/lang/wgsl/inspector/inspector_builder_test.h
+++ /dev/null
@@ -1,362 +0,0 @@
-// Copyright 2021 The Dawn & Tint Authors
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice, this
-//    list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-//    this list of conditions and the following disclaimer in the documentation
-//    and/or other materials provided with the distribution.
-//
-// 3. Neither the name of the copyright holder nor the names of its
-//    contributors may be used to endorse or promote products derived from
-//    this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef SRC_TINT_LANG_WGSL_INSPECTOR_INSPECTOR_BUILDER_TEST_H_
-#define SRC_TINT_LANG_WGSL_INSPECTOR_INSPECTOR_BUILDER_TEST_H_
-
-#include <memory>
-#include <string>
-#include <tuple>
-#include <vector>
-
-#include "src/tint/lang/core/type/depth_texture.h"
-#include "src/tint/lang/core/type/external_texture.h"
-#include "src/tint/lang/core/type/multisampled_texture.h"
-#include "src/tint/lang/core/type/sampled_texture.h"
-#include "src/tint/lang/core/type/texture_dimension.h"
-#include "src/tint/lang/wgsl/ast/call_statement.h"
-#include "src/tint/lang/wgsl/ast/disable_validation_attribute.h"
-#include "src/tint/lang/wgsl/ast/id_attribute.h"
-#include "src/tint/lang/wgsl/ast/stage_attribute.h"
-#include "src/tint/lang/wgsl/ast/workgroup_attribute.h"
-#include "src/tint/lang/wgsl/inspector/entry_point.h"
-#include "src/tint/lang/wgsl/inspector/inspector.h"
-#include "src/tint/lang/wgsl/inspector/resource_binding.h"
-#include "src/tint/lang/wgsl/program/program_builder.h"
-#include "src/tint/lang/wgsl/sem/variable.h"
-
-namespace tint::inspector {
-
-/// Utility class for building programs in inspector tests
-class InspectorBuilder : public ProgramBuilder {
-  public:
-    InspectorBuilder();
-    ~InspectorBuilder();
-
-    /// Create a Program with Inspector from the provided WGSL shader.
-    /// Should only be called once per test and cannot be used with Build.
-    /// @param shader a WGSL shader
-    /// @returns a reference to the Inspector for the built Program.
-    Inspector& Initialize(std::string shader);
-
-    /// Build the Program given all of the previous methods called and return an
-    /// Inspector for it.
-    /// Should only be called once per test and cannot be used with Initialize.
-    /// @returns a reference to the Inspector for the built Program.
-    Inspector& Build();
-
-    /// Generates an empty function
-    /// @param name name of the function created
-    /// @param attributes the function attributes
-    void MakeEmptyBodyFunction(std::string name, VectorRef<const ast::Attribute*> attributes);
-
-    /// Generates a function that calls other functions
-    /// @param caller name of the function created
-    /// @param callees names of the functions to be called
-    /// @param attributes the function attributes
-    void MakeCallerBodyFunction(std::string caller,
-                                VectorRef<std::string> callees,
-                                VectorRef<const ast::Attribute*> attributes);
-
-    /// InOutInfo is a tuple of name and location for a structure member
-    using InOutInfo = std::tuple<std::string, uint32_t>;
-
-    /// Generates a struct that contains user-defined IO members
-    /// @param name the name of the generated struct
-    /// @param inout_vars tuples of {name, loc} that will be the struct members
-    /// @returns a structure object
-    const ast::Struct* MakeInOutStruct(std::string name, VectorRef<InOutInfo> inout_vars);
-
-    // TODO(crbug.com/tint/697): Remove this.
-    /// Add In/Out variables to the global variables
-    /// @param inout_vars tuples of {in, out} that will be added as entries to the
-    ///                   global variables
-    void AddInOutVariables(VectorRef<std::tuple<std::string, std::string>> inout_vars);
-
-    // TODO(crbug.com/tint/697): Remove this.
-    /// Generates a function that references in/out variables
-    /// @param name name of the function created
-    /// @param inout_vars tuples of {in, out} that will be converted into out = in
-    ///                   calls in the function body
-    /// @param attributes the function attributes
-    void MakeInOutVariableBodyFunction(std::string name,
-                                       VectorRef<std::tuple<std::string, std::string>> inout_vars,
-                                       VectorRef<const ast::Attribute*> attributes);
-
-    // TODO(crbug.com/tint/697): Remove this.
-    /// Generates a function that references in/out variables and calls another
-    /// function.
-    /// @param caller name of the function created
-    /// @param callee name of the function to be called
-    /// @param inout_vars tuples of {in, out} that will be converted into out = in
-    ///                   calls in the function body
-    /// @param attributes the function attributes
-    /// @returns a function object
-    const ast::Function* MakeInOutVariableCallerBodyFunction(
-        std::string caller,
-        std::string callee,
-        VectorRef<std::tuple<std::string, std::string>> inout_vars,
-        VectorRef<const ast::Attribute*> attributes);
-
-    /// Generates a function that references module-scoped, plain-typed constant
-    /// or variable.
-    /// @param func name of the function created
-    /// @param var name of the constant to be reference
-    /// @param type type of the const being referenced
-    /// @param attributes the function attributes
-    /// @returns a function object
-    const ast::Function* MakePlainGlobalReferenceBodyFunction(
-        std::string func,
-        std::string var,
-        ast::Type type,
-        VectorRef<const ast::Attribute*> attributes);
-
-    /// @param vec Vector of StageVariable to be searched
-    /// @param name Name to be searching for
-    /// @returns true if name is in vec, otherwise false
-    bool ContainsName(VectorRef<StageVariable> vec, const std::string& name);
-
-    /// Builds a string for accessing a member in a generated struct
-    /// @param idx index of member
-    /// @param type type of member
-    /// @returns a string for the member
-    std::string StructMemberName(size_t idx, ast::Type type);
-
-    /// Generates a struct type
-    /// @param name name for the type
-    /// @param member_types a vector of member types
-    /// @returns a struct type
-    const ast::Struct* MakeStructType(const std::string& name, VectorRef<ast::Type> member_types);
-
-    /// Generates a struct type from a list of member nodes.
-    /// @param name name for the struct type
-    /// @param members a vector of members
-    /// @returns a struct type
-    const ast::Struct* MakeStructTypeFromMembers(const std::string& name,
-                                                 VectorRef<const ast::StructMember*> members);
-
-    /// Generates a struct member with a specified index and type.
-    /// @param index index of the field within the struct
-    /// @param type the type of the member field
-    /// @param attributes a list of attributes to apply to the member field
-    /// @returns a struct member
-    const ast::StructMember* MakeStructMember(size_t index,
-                                              ast::Type type,
-                                              VectorRef<const ast::Attribute*> attributes);
-
-    /// Generates types appropriate for using in an uniform buffer
-    /// @param name name for the type
-    /// @param member_types a vector of member types
-    /// @returns a struct type that has the layout for an uniform buffer.
-    const ast::Struct* MakeUniformBufferType(const std::string& name,
-                                             VectorRef<ast::Type> member_types);
-
-    /// Generates types appropriate for using in a storage buffer
-    /// @param name name for the type
-    /// @param member_types a vector of member types
-    /// @returns a function that returns the created structure.
-    std::function<ast::Type()> MakeStorageBufferTypes(const std::string& name,
-                                                      VectorRef<ast::Type> member_types);
-
-    /// Adds an uniform buffer variable to the program
-    /// @param name the name of the variable
-    /// @param type the type to use
-    /// @param group the binding/group/ to use for the uniform buffer
-    /// @param binding the binding number to use for the uniform buffer
-    void AddUniformBuffer(const std::string& name,
-                          ast::Type type,
-                          uint32_t group,
-                          uint32_t binding);
-
-    /// Adds a workgroup storage variable to the program
-    /// @param name the name of the variable
-    /// @param type the type of the variable
-    void AddWorkgroupStorage(const std::string& name, ast::Type type);
-
-    /// Adds a storage buffer variable to the program
-    /// @param name the name of the variable
-    /// @param type the type to use
-    /// @param access the storage buffer access control
-    /// @param group the binding/group to use for the storage buffer
-    /// @param binding the binding number to use for the storage buffer
-    void AddStorageBuffer(const std::string& name,
-                          ast::Type type,
-                          core::Access access,
-                          uint32_t group,
-                          uint32_t binding);
-
-    /// MemberInfo is a tuple of member index and type.
-    using MemberInfo = std::tuple<size_t, ast::Type>;
-
-    /// Generates a function that references a specific struct variable
-    /// @param func_name name of the function created
-    /// @param struct_name name of the struct variabler to be accessed
-    /// @param members list of members to access, by index and type
-    void MakeStructVariableReferenceBodyFunction(std::string func_name,
-                                                 std::string struct_name,
-                                                 VectorRef<MemberInfo> members);
-
-    /// Adds a regular sampler variable to the program
-    /// @param name the name of the variable
-    /// @param group the binding/group to use for the storage buffer
-    /// @param binding the binding number to use for the storage buffer
-    void AddSampler(const std::string& name, uint32_t group, uint32_t binding);
-
-    /// Adds a comparison sampler variable to the program
-    /// @param name the name of the variable
-    /// @param group the binding/group to use for the storage buffer
-    /// @param binding the binding number to use for the storage buffer
-    void AddComparisonSampler(const std::string& name, uint32_t group, uint32_t binding);
-
-    /// Adds a sampler or texture variable to the program
-    /// @param name the name of the variable
-    /// @param type the type to use
-    /// @param group the binding/group to use for the resource
-    /// @param binding the binding number to use for the resource
-    void AddResource(const std::string& name, ast::Type type, uint32_t group, uint32_t binding);
-
-    /// Add a module scope private variable to the progames
-    /// @param name the name of the variable
-    /// @param type the type to use
-    void AddGlobalVariable(const std::string& name, ast::Type type);
-
-    /// Generates a function that references a specific sampler variable
-    /// @param func_name name of the function created
-    /// @param texture_name name of the texture to be sampled
-    /// @param sampler_name name of the sampler to use
-    /// @param coords_name name of the coords variable to use
-    /// @param base_type sampler base type
-    /// @param attributes the function attributes
-    /// @returns a function that references all of the values specified
-    const ast::Function* MakeSamplerReferenceBodyFunction(
-        const std::string& func_name,
-        const std::string& texture_name,
-        const std::string& sampler_name,
-        const std::string& coords_name,
-        ast::Type base_type,
-        VectorRef<const ast::Attribute*> attributes);
-
-    /// Generates a function that references a specific sampler variable
-    /// @param func_name name of the function created
-    /// @param texture_name name of the texture to be sampled
-    /// @param sampler_name name of the sampler to use
-    /// @param coords_name name of the coords variable to use
-    /// @param array_index name of the array index variable to use
-    /// @param base_type sampler base type
-    /// @param attributes the function attributes
-    /// @returns a function that references all of the values specified
-    const ast::Function* MakeSamplerReferenceBodyFunction(
-        const std::string& func_name,
-        const std::string& texture_name,
-        const std::string& sampler_name,
-        const std::string& coords_name,
-        const std::string& array_index,
-        ast::Type base_type,
-        VectorRef<const ast::Attribute*> attributes);
-
-    /// Generates a function that references a specific comparison sampler
-    /// variable.
-    /// @param func_name name of the function created
-    /// @param texture_name name of the depth texture to  use
-    /// @param sampler_name name of the sampler to use
-    /// @param coords_name name of the coords variable to use
-    /// @param depth_name name of the depth reference to use
-    /// @param base_type sampler base type
-    /// @param attributes the function attributes
-    /// @returns a function that references all of the values specified
-    const ast::Function* MakeComparisonSamplerReferenceBodyFunction(
-        const std::string& func_name,
-        const std::string& texture_name,
-        const std::string& sampler_name,
-        const std::string& coords_name,
-        const std::string& depth_name,
-        ast::Type base_type,
-        VectorRef<const ast::Attribute*> attributes);
-
-    /// Gets an appropriate type for the data in a given texture type.
-    /// @param sampled_kind type of in the texture
-    /// @returns a pointer to a type appropriate for the coord param
-    ast::Type GetBaseType(ResourceBinding::SampledKind sampled_kind);
-
-    /// Gets an appropriate type for the coords parameter depending the
-    /// dimensionality of the texture being sampled.
-    /// @param dim dimensionality of the texture being sampled
-    /// @param scalar the scalar type
-    /// @returns a pointer to a type appropriate for the coord param
-    ast::Type GetCoordsType(core::type::TextureDimension dim, ast::Type scalar);
-
-    /// Generates appropriate types for a StorageTexture
-    /// @param dim the texture dimension of the storage texture
-    /// @param format the texel format of the storage texture
-    /// @param access the storage texture access
-    /// @returns the storage texture type
-    ast::Type MakeStorageTextureTypes(core::type::TextureDimension dim,
-                                      core::TexelFormat format,
-                                      core::Access access);
-
-    /// Adds a storage texture variable to the program
-    /// @param name the name of the variable
-    /// @param type the type to use
-    /// @param group the binding/group to use for the sampled texture
-    /// @param binding the binding57 number to use for the sampled texture
-    void AddStorageTexture(const std::string& name,
-                           ast::Type type,
-                           uint32_t group,
-                           uint32_t binding);
-
-    /// Generates a function that references a storage texture variable.
-    /// @param func_name name of the function created
-    /// @param st_name name of the storage texture to use
-    /// @param dim_type type expected by textureDimensons to return
-    /// @param attributes the function attributes
-    /// @returns a function that references all of the values specified
-    const ast::Function* MakeStorageTextureBodyFunction(
-        const std::string& func_name,
-        const std::string& st_name,
-        ast::Type dim_type,
-        VectorRef<const ast::Attribute*> attributes);
-
-    /// Get a generator function that returns a type appropriate for a stage
-    /// variable with the given combination of component and composition type.
-    /// @param component component type of the stage variable
-    /// @param composition composition type of the stage variable
-    /// @returns a generator function for the stage variable's type.
-    std::function<ast::Type()> GetTypeFunction(ComponentType component,
-                                               CompositionType composition);
-
-  protected:
-    /// File created from input shader and used to create Program.
-    std::unique_ptr<Source::File> file_;
-    /// Program created by this runner.
-    std::unique_ptr<Program> program_;
-    /// Inspector for |program_|
-    std::unique_ptr<Inspector> inspector_;
-};
-
-}  // namespace tint::inspector
-
-#endif  // SRC_TINT_LANG_WGSL_INSPECTOR_INSPECTOR_BUILDER_TEST_H_
diff --git a/src/tint/lang/wgsl/inspector/inspector_test.cc b/src/tint/lang/wgsl/inspector/inspector_test.cc
index a5d013a..56a617c 100644
--- a/src/tint/lang/wgsl/inspector/inspector_test.cc
+++ b/src/tint/lang/wgsl/inspector/inspector_test.cc
@@ -31,21 +31,9 @@
 #include "gmock/gmock.h"
 
 #include "src/tint/lang/core/fluent_types.h"
-#include "src/tint/lang/core/type/depth_texture.h"
-#include "src/tint/lang/core/type/external_texture.h"
-#include "src/tint/lang/core/type/multisampled_texture.h"
-#include "src/tint/lang/core/type/sampled_texture.h"
-#include "src/tint/lang/core/type/texture_dimension.h"
-#include "src/tint/lang/wgsl/ast/call_statement.h"
-#include "src/tint/lang/wgsl/ast/disable_validation_attribute.h"
-#include "src/tint/lang/wgsl/ast/id_attribute.h"
-#include "src/tint/lang/wgsl/ast/stage_attribute.h"
-#include "src/tint/lang/wgsl/ast/workgroup_attribute.h"
 #include "src/tint/lang/wgsl/inspector/entry_point.h"
 #include "src/tint/lang/wgsl/inspector/inspector.h"
-#include "src/tint/lang/wgsl/inspector/inspector_builder_test.h"
-#include "src/tint/lang/wgsl/program/program_builder.h"
-#include "src/tint/lang/wgsl/sem/variable.h"
+#include "src/tint/lang/wgsl/reader/reader.h"
 
 using namespace tint::core::number_suffixes;  // NOLINT
 using namespace tint::core::fluent_types;     // NOLINT
@@ -53,81 +41,61 @@
 namespace tint::inspector {
 namespace {
 
-// All the tests that descend from InspectorBuilder are expected to define their test state
-// either:
-//  - via building up the AST through InspectorBuilder methods and then generate the program with
-//    ::Build. The returned Inspector from ::Build can then be used to test expectations.
-//  - via a WGSL shader, which will be parsed to generate a Program and Inspector in ::Initialize.
-//    The returned Inspector from ::Initialize can then be used to test expectations.
+/// Utility class for building programs in inspector tests
+class TestHelper {
+  public:
+    /// Create a Program with Inspector from the provided WGSL shader.
+    /// Should only be called once per test and cannot be used with Build.
+    /// @param shader a WGSL shader
+    /// @returns a reference to the Inspector for the built Program.
+    Inspector& Initialize(std::string shader) {
+        if (inspector_) {
+            return *inspector_;
+        }
 
-class InspectorGetEntryPointTest : public InspectorBuilder, public testing::Test {};
-class InspectorOverridesTest : public InspectorBuilder, public testing::Test {};
+        wgsl::reader::Options options;
+        options.allowed_features = wgsl::AllowedFeatures::Everything();
+        file_ = std::make_unique<Source::File>("test", shader);
+        program_ = std::make_unique<Program>(wgsl::reader::Parse(file_.get(), options));
+        if (!program_->IsValid()) {
+            ADD_FAILURE() << program_->Diagnostics();
+        }
+        inspector_ = std::make_unique<Inspector>(*program_);
+        return *inspector_;
+    }
 
-typedef std::tuple<inspector::ComponentType, inspector::CompositionType>
-    InspectorGetEntryPointComponentAndCompositionTestParams;
-class InspectorGetEntryPointComponentAndCompositionTest
-    : public InspectorBuilder,
-      public testing::TestWithParam<InspectorGetEntryPointComponentAndCompositionTestParams> {};
-struct InspectorGetEntryPointInterpolateTestParams {
-    core::InterpolationType in_type;
-    core::InterpolationSampling in_sampling;
-    inspector::InterpolationType out_type;
-    inspector::InterpolationSampling out_sampling;
+  protected:
+    /// File created from input shader and used to create Program.
+    std::unique_ptr<Source::File> file_;
+    /// Program created by this runner.
+    std::unique_ptr<Program> program_;
+    /// Inspector for |program_|
+    std::unique_ptr<Inspector> inspector_;
 };
-class InspectorGetEntryPointInterpolateTest
-    : public InspectorBuilder,
-      public testing::TestWithParam<InspectorGetEntryPointInterpolateTestParams> {};
-class InspectorGetOverrideDefaultValuesTest : public InspectorBuilder, public testing::Test {};
-class InspectorGetConstantNameToIdMapTest : public InspectorBuilder, public testing::Test {};
 
-class InspectorGetResourceBindingsTest : public InspectorBuilder, public testing::Test {};
-struct SampledTextureTestParams {
-    core::type::TextureDimension type_dim;
-    inspector::ResourceBinding::TextureDimension inspector_dim;
-    inspector::ResourceBinding::SampledKind sampled_kind;
-};
-class InspectorGetResourceBindingsTest_WithSampledTextureParams
-    : public InspectorBuilder,
-      public testing::TestWithParam<SampledTextureTestParams> {};
-using ArraySampledTextureTestParams = SampledTextureTestParams;
-class InspectorGetResourceBindingsTest_WithArraySampledTextureParams
-    : public InspectorBuilder,
-      public testing::TestWithParam<ArraySampledTextureTestParams> {};
-using MultisampledTextureTestParams = SampledTextureTestParams;
-class InspectorGetResourceBindingsTest_WithMultisampledTextureParams
-    : public InspectorBuilder,
-      public testing::TestWithParam<MultisampledTextureTestParams> {};
-struct DepthTextureTestParams {
-    core::type::TextureDimension type_dim;
-    inspector::ResourceBinding::TextureDimension inspector_dim;
-};
-class InspectorGetResourceBindingsTest_WithDepthTextureParams
-    : public InspectorBuilder,
-      public testing::TestWithParam<DepthTextureTestParams> {};
-using DimensionParams = std::tuple<core::type::TextureDimension, ResourceBinding::TextureDimension>;
-using TexelFormatParams =
-    std::tuple<core::TexelFormat, ResourceBinding::TexelFormat, ResourceBinding::SampledKind>;
-using StorageTextureTestParams = std::tuple<DimensionParams, TexelFormatParams, core::Access>;
-class InspectorGetResourceBindingsTest_WithStorageTextureParams
-    : public InspectorBuilder,
-      public testing::TestWithParam<StorageTextureTestParams> {};
+class InspectorTest : public TestHelper, public testing::Test {};
 
-class InspectorGetUsedExtensionNamesTest : public InspectorBuilder, public testing::Test {};
+template <typename T>
+class InspectorTestWithParam : public TestHelper, public testing::TestWithParam<T> {};
 
-class InspectorGetEnableDirectivesTest : public InspectorBuilder, public testing::Test {};
+using InspectorGetEntryPointTest = InspectorTest;
+using InspectorOverridesTest = InspectorTest;
+using InspectorGetOverrideDefaultValuesTest = InspectorTest;
+using InspectorGetConstantNameToIdMapTest = InspectorTest;
+using InspectorGetResourceBindingsTest = InspectorTest;
+using InspectorGetUsedExtensionNamesTest = InspectorTest;
+using InspectorGetEnableDirectivesTest = InspectorTest;
+using InspectorGetBlendSrcTest = InspectorTest;
+using InspectorSubgroupMatrixTest = InspectorTest;
+using InspectorTextureTest = InspectorTest;
 
-class InspectorGetBlendSrcTest : public InspectorBuilder, public testing::Test {};
-
-class InspectorSubgroupMatrixTest : public InspectorBuilder, public testing::Test {};
-
-class InspectorTextureTest : public InspectorBuilder, public testing::Test {};
-
-// This is a catch all for shaders that have demonstrated regressions/crashes in
-// the wild.
-class InspectorRegressionTest : public InspectorBuilder, public testing::Test {};
+// This is a catch all for shaders that have demonstrated regressions/crashes in the wild.
+using InspectorRegressionTest = InspectorTest;
 
 TEST_F(InspectorGetEntryPointTest, NoFunctions) {
-    Inspector& inspector = Build();
+    auto* src = R"(
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -136,7 +104,10 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, NoEntryPoints) {
-    Inspector& inspector = Build();
+    auto* src = R"(
+fn foo() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -145,13 +116,10 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OneEntryPoint) {
-    MakeEmptyBodyFunction("foo", Vector{
-                                     Stage(ast::PipelineStage::kFragment),
-                                 });
-
-    // TODO(dsinclair): Update to run the namer transform when available.
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment fn foo() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -163,18 +131,11 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, MultipleEntryPoints) {
-    MakeEmptyBodyFunction("foo", Vector{
-                                     Stage(ast::PipelineStage::kFragment),
-                                 });
-
-    MakeEmptyBodyFunction("bar", Vector{
-                                     Stage(ast::PipelineStage::kCompute),
-                                     WorkgroupSize(1_i),
-                                 });
-
-    // TODO(dsinclair): Update to run the namer transform when available.
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment fn foo() {}
+@compute @workgroup_size(1i) fn bar() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -189,22 +150,15 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, MixFunctionsAndEntryPoints) {
-    MakeEmptyBodyFunction("func", tint::Empty);
+    auto* src = R"(
+fn func() {}
 
-    MakeCallerBodyFunction("foo", Vector{std::string("func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kCompute),
-                               WorkgroupSize(1_i),
-                           });
+@compute @workgroup_size(1i)
+fn foo() { func(); }
 
-    MakeCallerBodyFunction("bar", Vector{std::string("func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    // TODO(dsinclair): Update to run the namer transform when available.
-
-    Inspector& inspector = Build();
+@fragment fn bar() { func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     EXPECT_FALSE(inspector.has_error());
@@ -219,12 +173,10 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, DefaultWorkgroupSize) {
-    MakeEmptyBodyFunction("foo", Vector{
-                                     Stage(ast::PipelineStage::kCompute),
-                                     WorkgroupSize(8_i, 2_i, 1_i),
-                                 });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@compute @workgroup_size(8i, 2i, 1i)  fn foo() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -239,11 +191,10 @@
 
 // Test that push_constant_size is zero if there are no push constants.
 TEST_F(InspectorGetEntryPointTest, PushConstantSizeNone) {
-    MakeEmptyBodyFunction("foo", Vector{
-                                     Stage(ast::PipelineStage::kFragment),
-                                 });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment fn foo() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -254,14 +205,14 @@
 
 // Test that push_constant_size is 4 (bytes) if there is a single F32 push constant.
 TEST_F(InspectorGetEntryPointTest, PushConstantSizeOneWord) {
-    Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
-    GlobalVar("pc", core::AddressSpace::kPushConstant, ty.f32());
-    MakePlainGlobalReferenceBodyFunction("foo", "pc", ty.f32(),
-                                         Vector{
-                                             Stage(ast::PipelineStage::kFragment),
-                                         });
+    auto* src = R"(
+enable chromium_experimental_push_constant;
 
-    Inspector& inspector = Build();
+var<push_constant> pc: f32;
+
+@fragment fn foo() { _ = pc; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -273,16 +224,19 @@
 // Test that push_constant_size is 12 (bytes) if there is a struct containing one
 // each of i32, f32 and u32.
 TEST_F(InspectorGetEntryPointTest, PushConstantSizeThreeWords) {
-    Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
-    auto* pc_struct_type =
-        MakeStructType("PushConstantStruct", Vector{ty.i32(), ty.f32(), ty.u32()});
-    GlobalVar("pc", core::AddressSpace::kPushConstant, ty.Of(pc_struct_type));
-    MakePlainGlobalReferenceBodyFunction("foo", "pc", ty.Of(pc_struct_type),
-                                         Vector{
-                                             Stage(ast::PipelineStage::kFragment),
-                                         });
+    auto* src = R"(
+enable chromium_experimental_push_constant;
 
-    Inspector& inspector = Build();
+struct S {
+  a: i32,
+  b: f32,
+  c: u32,
+}
+var<push_constant> pc : S;
+
+@fragment fn foo() { _ = pc; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -295,17 +249,20 @@
 // one used by the entry point containing an f32, and one unused by the entry
 // point containing a struct of size 12 bytes.
 TEST_F(InspectorGetEntryPointTest, PushConstantSizeTwoConstants) {
-    Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
-    auto* unused_struct_type =
-        MakeStructType("PushConstantStruct", Vector{ty.i32(), ty.f32(), ty.u32()});
-    GlobalVar("unused", core::AddressSpace::kPushConstant, ty.Of(unused_struct_type));
-    GlobalVar("pc", core::AddressSpace::kPushConstant, ty.f32());
-    MakePlainGlobalReferenceBodyFunction("foo", "pc", ty.f32(),
-                                         Vector{
-                                             Stage(ast::PipelineStage::kFragment),
-                                         });
+    auto* src = R"(
+enable chromium_experimental_push_constant;
 
-    Inspector& inspector = Build();
+struct S {
+  a: i32,
+  b: f32,
+  c: u32,
+}
+var<push_constant> unused : S;
+var<push_constant> pc: f32;
+
+@fragment fn foo() { _ = pc; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -317,12 +274,11 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, NonDefaultWorkgroupSize) {
-    MakeEmptyBodyFunction("foo", Vector{
-                                     Stage(ast::PipelineStage::kCompute),
-                                     WorkgroupSize(8_i, 2_i, 1_i),
-                                 });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@compute @workgroup_size(8i, 2i, 1i)
+fn foo() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -336,11 +292,11 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, WorkgroupStorageSizeEmpty) {
-    MakeEmptyBodyFunction("ep_func", Vector{
-                                         Stage(ast::PipelineStage::kCompute),
-                                         WorkgroupSize(1_i),
-                                     });
-    Inspector& inspector = Build();
+    auto* src = R"(
+@compute @workgroup_size(1i)
+fn ep_func() {}
+)";
+    Inspector& inspector = Initialize(src);
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
@@ -349,18 +305,20 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, WorkgroupStorageSizeSimple) {
-    AddWorkgroupStorage("wg_f32", ty.f32());
-    AddWorkgroupStorage("wg_i32", ty.i32());
-    MakePlainGlobalReferenceBodyFunction("f32_func", "wg_f32", ty.f32(), tint::Empty);
-    MakePlainGlobalReferenceBodyFunction("i32_func", "wg_i32", ty.i32(), tint::Empty);
+    auto* src = R"(
+var<workgroup> wg_f32: f32;
+var<workgroup> wg_i32: i32;
 
-    MakeCallerBodyFunction("ep_func", Vector{std::string("f32_func"), "i32_func"},
-                           Vector{
-                               Stage(ast::PipelineStage::kCompute),
-                               WorkgroupSize(1_i),
-                           });
+fn f32_func() { _ = wg_f32; }
+fn i32_func() { _ = wg_i32; }
 
-    Inspector& inspector = Build();
+@compute @workgroup_size(1i)
+fn ep_func() {
+  f32_func();
+  i32_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
@@ -369,31 +327,27 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, WorkgroupStorageSizeCompoundTypes) {
-    // This struct should occupy 68 bytes. 4 from the i32 field, and another 64
-    // from the 4-element array with 16-byte stride.
-    auto* wg_struct_type = MakeStructType("WgStruct", Vector{
-                                                          ty.i32(),
-                                                          ty.array<i32, 4>(Vector{
-                                                              Stride(16),
-                                                          }),
-                                                      });
-    AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
-    MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                            });
+    auto* src = R"(
+// This struct should occupy 68 bytes.
+struct WgStruct {
+  a: i32,
+  b: array<i32, 16>,
+}
+var<workgroup> wg_struct_var: WgStruct;
 
-    // Plus another 4 bytes from this other workgroup-class f32.
-    AddWorkgroupStorage("wg_f32", ty.f32());
-    MakePlainGlobalReferenceBodyFunction("f32_func", "wg_f32", ty.f32(), tint::Empty);
+fn wg_struct_func() { _ = wg_struct_var.a; }
 
-    MakeCallerBodyFunction("ep_func", Vector{std::string("wg_struct_func"), "f32_func"},
-                           Vector{
-                               Stage(ast::PipelineStage::kCompute),
-                               WorkgroupSize(1_i),
-                           });
+// Plus another 4 bytes from this other workgroup-class f32.
+var<workgroup> wg_f32: f32;
+fn f32_func() { _ = wg_f32; }
 
-    Inspector& inspector = Build();
+@compute @workgroup_size(1i)
+fn ep_func() {
+  wg_struct_func();
+  f32_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
@@ -402,18 +356,19 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, WorkgroupStorageSizeAlignmentPadding) {
-    // vec3<f32> has an alignment of 16 but a size of 12. We leverage this to test
-    // that our padded size calculation for workgroup storage is accurate.
-    AddWorkgroupStorage("wg_vec3", ty.vec3<f32>());
-    MakePlainGlobalReferenceBodyFunction("wg_func", "wg_vec3", ty.vec3<f32>(), tint::Empty);
+    auto* src = R"(
+// vec3<f32> has an alignment of 16 but a size of 12. We leverage this to test
+// that our padded size calculation for workgroup storage is accurate.
+var<workgroup> wg_vec3: vec3f;
 
-    MakeCallerBodyFunction("ep_func", Vector{std::string("wg_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kCompute),
-                               WorkgroupSize(1_i),
-                           });
+fn wg_func() { _ = wg_vec3; }
 
-    Inspector& inspector = Build();
+@compute @workgroup_size(1i)
+fn ep_func() {
+  wg_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
@@ -422,27 +377,23 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, WorkgroupStorageSizeStructAlignment) {
-    // Per WGSL spec, a struct's size is the offset its last member plus the size
-    // of its last member, rounded up to the alignment of its largest member. So
-    // here the struct is expected to occupy 1024 bytes of workgroup storage.
-    const auto* wg_struct_type = MakeStructTypeFromMembers(
-        "WgStruct", Vector{
-                        MakeStructMember(0, ty.f32(), Vector{MemberAlign(1024_i)}),
-                    });
+    auto* src = R"(
+// Per WGSL spec, a struct's size is the offset its last member plus the size
+// of its last member, rounded up to the alignment of its largest member. So
+// here the struct is expected to occupy 1024 bytes of workgroup storage.
+struct WgStruct {
+  @align(1024i) a: f32,
+}
+var<workgroup> wg_struct_var: WgStruct;
 
-    AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
-    MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var",
-                                            Vector{
-                                                MemberInfo{0, ty.f32()},
-                                            });
+fn wg_struct_func() { _ = wg_struct_var.a; }
 
-    MakeCallerBodyFunction("ep_func", Vector{std::string("wg_struct_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kCompute),
-                               WorkgroupSize(1_i),
-                           });
-
-    Inspector& inspector = Build();
+@compute @workgroup_size(1i)
+fn ep_func() {
+  wg_struct_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
@@ -451,14 +402,11 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
-    MakeEmptyBodyFunction("func", tint::Empty);
-
-    MakeCallerBodyFunction("foo", Vector{std::string("func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+fn func() {}
+@fragment fn foo() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -468,32 +416,68 @@
     EXPECT_EQ(0u, result[0].output_variables.size());
 }
 
+std::string GetType(ComponentType component, CompositionType composition) {
+    std::string comp;
+    switch (component) {
+        case ComponentType::kF32:
+            comp = "f32";
+            break;
+        case ComponentType::kI32:
+            comp = "i32";
+            break;
+        case ComponentType::kU32:
+            comp = "u32";
+            break;
+        case ComponentType::kF16:
+            comp = "f16";
+            break;
+        case ComponentType::kUnknown:
+            TINT_UNREACHABLE();
+    }
+
+    uint32_t n;
+    switch (composition) {
+        case CompositionType::kScalar:
+            return comp;
+        case CompositionType::kVec2:
+            n = 2;
+            break;
+        case CompositionType::kVec3:
+            n = 3;
+            break;
+        case CompositionType::kVec4:
+            n = 4;
+            break;
+        default:
+            TINT_UNREACHABLE();
+    }
+    return std::string("vec") + std::to_string(n) + "<" + comp + ">";
+}
+
+typedef std::tuple<inspector::ComponentType, inspector::CompositionType>
+    InspectorGetEntryPointComponentAndCompositionTestParams;
+using InspectorGetEntryPointComponentAndCompositionTest =
+    InspectorTestWithParam<InspectorGetEntryPointComponentAndCompositionTestParams>;
+
 TEST_P(InspectorGetEntryPointComponentAndCompositionTest, Test) {
     ComponentType component;
     CompositionType composition;
     std::tie(component, composition) = GetParam();
-    std::function<ast::Type()> tint_type = GetTypeFunction(component, composition);
 
+    std::string src = "";
     if (component == ComponentType::kF16) {
-        Enable(wgsl::Extension::kF16);
+        src += "enable f16;\n";
     }
 
-    auto* in_var = Param("in_var", tint_type(),
-                         Vector{
-                             Location(0_u),
-                             Flat(),
-                         });
-    Func("foo", Vector{in_var}, tint_type(),
-         Vector{
-             Return("in_var"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         },
-         Vector{
-             Location(0_u),
-         });
-    Inspector& inspector = Build();
+    auto tint_type = GetType(component, composition);
+    src += R"(
+@fragment
+fn foo(@location(0u) @interpolate(flat) in_var: )" +
+           tint_type + ") -> @location(0) " + tint_type + R"( {
+  return in_var;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -524,33 +508,15 @@
                                                           CompositionType::kVec4)));
 
 TEST_F(InspectorGetEntryPointTest, MultipleInOutVariables) {
-    Enable(wgsl::Extension::kChromiumExperimentalFramebufferFetch);
+    auto* src = R"(
+enable chromium_experimental_framebuffer_fetch;
 
-    auto* in_var0 = Param("in_var0", ty.u32(),
-                          Vector{
-                              Location(0_u),
-                              Flat(),
-                          });
-    auto* in_var1 = Param("in_var1", ty.u32(),
-                          Vector{
-                              Location(1_u),
-                              Flat(),
-                          });
-    auto* in_var4 = Param("in_var4", ty.u32(),
-                          Vector{
-                              Color(2_u),
-                          });
-    Func("foo", Vector{in_var0, in_var1, in_var4}, ty.u32(),
-         Vector{
-             Return("in_var0"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         },
-         Vector{
-             Location(0_u),
-         });
-    Inspector& inspector = Build();
+@fragment
+fn foo(@location(0u) @interpolate(flat) in_var0: u32, @location(1u) @interpolate(flat) in_var1: u32, @color(2u) in_var4: u32) -> @location(0u) u32 {
+  return in_var0;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -586,39 +552,18 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) {
-    auto* in_var_foo = Param("in_var_foo", ty.u32(),
-                             Vector{
-                                 Location(0_u),
-                                 Flat(),
-                             });
-    Func("foo", Vector{in_var_foo}, ty.u32(),
-         Vector{
-             Return("in_var_foo"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         },
-         Vector{
-             Location(0_u),
-         });
+    auto* src = R"(
+@fragment
+fn foo(@location(0u) @interpolate(flat) in_var_foo: u32) -> @location(0) u32 {
+  return in_var_foo;
+}
 
-    auto* in_var_bar = Param("in_var_bar", ty.u32(),
-                             Vector{
-                                 Location(0_u),
-                                 Flat(),
-                             });
-    Func("bar", Vector{in_var_bar}, ty.u32(),
-         Vector{
-             Return("in_var_bar"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         },
-         Vector{
-             Location(1_u),
-         });
-
-    Inspector& inspector = Build();
+@fragment
+fn bar(@location(0u) @interpolate(flat) in_var_bar: u32) -> @location(1u) u32 {
+  return in_var_bar;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -653,25 +598,13 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, BuiltInsNotStageVariables) {
-    auto* in_var0 = Param("in_var0", ty.u32(),
-                          Vector{
-                              Builtin(core::BuiltinValue::kSampleIndex),
-                          });
-    auto* in_var1 = Param("in_var1", ty.f32(),
-                          Vector{
-                              Location(0_u),
-                          });
-    Func("foo", Vector{in_var0, in_var1}, ty.f32(),
-         Vector{
-             Return("in_var1"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         },
-         Vector{
-             Builtin(core::BuiltinValue::kFragDepth),
-         });
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment
+fn foo(@builtin(sample_index) in_var0: u32, @location(0u) in_var1: f32) -> @builtin(frag_depth) f32 {
+  return in_var1;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -688,22 +621,17 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, InOutStruct) {
-    auto* interface = MakeInOutStruct("interface", Vector{
-                                                       InOutInfo{"a", 0u},
-                                                       InOutInfo{"b", 1u},
-                                                   });
-    Func("foo",
-         Vector{
-             Param("param", ty.Of(interface)),
-         },
-         ty.Of(interface),
-         Vector{
-             Return("param"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct Interface {
+  @location(0u) @interpolate(flat) a: u32,
+  @location(1u) @interpolate(flat) b: u32,
+}
+@fragment
+fn foo(param: Interface) -> Interface {
+  return param;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -732,22 +660,20 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutSharedStruct) {
-    auto* interface = MakeInOutStruct("interface", Vector{
-                                                       InOutInfo{"a", 0u},
-                                                       InOutInfo{"b", 1u},
-                                                   });
-    Func("foo", tint::Empty, ty.Of(interface),
-         Vector{
-             Return(Call(ty.Of(interface))),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-    Func("bar", Vector{Param("param", ty.Of(interface))}, ty.void_(), tint::Empty,
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct Interface {
+  @location(0u) @interpolate(flat) a: u32,
+  @location(1u) @interpolate(flat) b: u32,
+}
+@fragment
+fn foo() -> Interface {
+  return Interface();
+}
+
+@fragment
+fn bar(param: Interface) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -780,28 +706,21 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, MixInOutVariablesAndStruct) {
-    auto* struct_a = MakeInOutStruct("struct_a", Vector{
-                                                     InOutInfo{"a", 0u},
-                                                     InOutInfo{"b", 1u},
-                                                 });
-    auto* struct_b = MakeInOutStruct("struct_b", Vector{
-                                                     InOutInfo{"a", 2u},
-                                                 });
-    Func("foo",
-         Vector{
-             Param("param_a", ty.Of(struct_a)),
-             Param("param_b", ty.Of(struct_b)),
-             Param("param_c", ty.f32(), Vector{Location(3_u)}),
-             Param("param_d", ty.f32(), Vector{Location(4_u)}),
-         },
-         ty.Of(struct_a),
-         Vector{
-             Return("param_a"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct struct_a {
+  @location(0u) @interpolate(flat) a: u32,
+  @location(1u) @interpolate(flat) b: u32,
+}
+struct struct_b {
+  @location(2u) @interpolate(flat) a: u32,
+}
+
+@fragment
+fn foo(param_a: struct_a, param_b: struct_b, @location(3u) param_c: f32, @location(4u) param_d: f32) -> struct_a {
+  return param_a;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -842,13 +761,13 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideUnreferenced) {
-    Override("foo", ty.f32());
-    MakeEmptyBodyFunction("ep_func", Vector{
-                                         Stage(ast::PipelineStage::kCompute),
-                                         WorkgroupSize(1_i),
-                                     });
+    auto* src = R"(
+override foo: f32;
 
-    Inspector& inspector = Build();
+@compute @workgroup_size(1i)
+fn ep_func() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -857,14 +776,13 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedByEntryPoint) {
-    Override("foo", ty.f32());
-    MakePlainGlobalReferenceBodyFunction("ep_func", "foo", ty.f32(),
-                                         Vector{
-                                             Stage(ast::PipelineStage::kCompute),
-                                             WorkgroupSize(1_i),
-                                         });
+    auto* src = R"(
+override foo: f32;
 
-    Inspector& inspector = Build();
+@compute @workgroup_size(1i)
+fn ep_func() { _ = foo; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -874,15 +792,17 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedByCallee) {
-    Override("foo", ty.f32());
-    MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), tint::Empty);
-    MakeCallerBodyFunction("ep_func", Vector{std::string("callee_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kCompute),
-                               WorkgroupSize(1_i),
-                           });
+    auto* src = R"(
+override foo: f32;
 
-    Inspector& inspector = Build();
+fn callee_func() { _ = foo; }
+
+@compute @workgroup_size(1i)
+fn ep_func() {
+  callee_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -892,16 +812,18 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideSomeReferenced) {
-    Override("foo", ty.f32(), Id(1_a));
-    Override("bar", ty.f32(), Id(2_a));
-    MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), tint::Empty);
-    MakeCallerBodyFunction("ep_func", Vector{std::string("callee_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kCompute),
-                               WorkgroupSize(1_i),
-                           });
+    auto* src = R"(
+@id(1) override foo: f32;
+@id(2) override bar: f32;
 
-    Inspector& inspector = Build();
+fn callee_fn() { _ = foo; }
+
+@compute @workgroup_size(1i)
+fn ep_func() {
+  callee_fn();
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -912,15 +834,14 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedIndirectly) {
-    Override("foo", ty.f32());
-    Override("bar", ty.f32(), Mul(2_a, "foo"));
-    MakePlainGlobalReferenceBodyFunction("ep_func", "bar", ty.f32(),
-                                         Vector{
-                                             Stage(ast::PipelineStage::kCompute),
-                                             WorkgroupSize(1_i),
-                                         });
+    auto* src = R"(
+override foo: f32;
+override bar: f32 = 2 * foo;
 
-    Inspector& inspector = Build();
+@compute @workgroup_size(1i)
+fn ep_func() { _ = bar; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -933,15 +854,14 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedIndirectly_ViaPrivateInitializer) {
-    Override("foo", ty.f32());
-    GlobalVar("bar", core::AddressSpace::kPrivate, ty.f32(), Mul(2_a, "foo"));
-    MakePlainGlobalReferenceBodyFunction("ep_func", "bar", ty.f32(),
-                                         Vector{
-                                             Stage(ast::PipelineStage::kCompute),
-                                             WorkgroupSize(1_i),
-                                         });
+    auto* src = R"(
+override foo: f32;
+var<private> bar: f32 = 2 * foo;
 
-    Inspector& inspector = Build();
+@compute @workgroup_size(1i)
+fn ep_func() { _ = bar; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -952,22 +872,18 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedIndirectly_MultipleEntryPoints) {
-    Override("foo1", ty.f32());
-    Override("bar1", ty.f32(), Mul(2_a, "foo1"));
-    MakePlainGlobalReferenceBodyFunction("ep_func1", "bar1", ty.f32(),
-                                         Vector{
-                                             Stage(ast::PipelineStage::kCompute),
-                                             WorkgroupSize(1_i),
-                                         });
-    Override("foo2", ty.f32());
-    Override("bar2", ty.f32(), Mul(2_a, "foo2"));
-    MakePlainGlobalReferenceBodyFunction("ep_func2", "bar2", ty.f32(),
-                                         Vector{
-                                             Stage(ast::PipelineStage::kCompute),
-                                             WorkgroupSize(1_i),
-                                         });
+    auto* src = R"(
+override foo1: f32;
+override bar1: f32 = 2 * foo1;
+@compute @workgroup_size(1i)
+fn ep_func1() { _ = bar1; }
 
-    Inspector& inspector = Build();
+override foo2: f32;
+override bar2: f32 = 2 * foo2;
+@compute @workgroup_size(1i)
+fn ep_func2() { _ = bar2; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -987,13 +903,12 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedByAttribute) {
-    Override("wgsize", ty.u32());
-    MakeEmptyBodyFunction("ep_func", Vector{
-                                         Stage(ast::PipelineStage::kCompute),
-                                         WorkgroupSize("wgsize"),
-                                     });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+override wgsize: u32;
+@compute @workgroup_size(wgsize)
+fn ep_func() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1004,14 +919,13 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedByAttributeIndirectly) {
-    Override("foo", ty.u32());
-    Override("bar", ty.u32(), Mul(2_a, "foo"));
-    MakeEmptyBodyFunction("ep_func", Vector{
-                                         Stage(ast::PipelineStage::kCompute),
-                                         WorkgroupSize(Mul(2_a, Expr("bar"))),
-                                     });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+override foo: u32;
+override bar: u32 = 2 * foo;
+@compute @workgroup_size(2 * bar)
+fn ep_func() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1024,18 +938,14 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedByArraySize) {
-    Override("size", ty.u32());
-    GlobalVar("v", core::AddressSpace::kWorkgroup, ty.array(ty.f32(), "size"));
-    Func("ep", tint::Empty, ty.void_(),
-         Vector{
-             Assign(Phony(), IndexAccessor("v", 0_a)),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kCompute),
-             WorkgroupSize(1_i),
-         });
+    auto* src = R"(
+override size: u32;
+var<workgroup> v: array<f32, size>;
 
-    Inspector& inspector = Build();
+@compute @workgroup_size(1i)
+fn ep() { _ = v[0]; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1046,19 +956,15 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedByArraySizeIndirectly) {
-    Override("foo", ty.u32());
-    Override("bar", ty.u32(), Mul(2_a, "foo"));
-    GlobalVar("v", core::AddressSpace::kWorkgroup, ty.array(ty.f32(), Mul(2_a, Expr("bar"))));
-    Func("ep", tint::Empty, ty.void_(),
-         Vector{
-             Assign(Phony(), IndexAccessor("v", 0_a)),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kCompute),
-             WorkgroupSize(1_i),
-         });
+    auto* src = R"(
+override foo: u32;
+override bar: u32 = 2 * foo;
+var<workgroup> v: array<f32, 2 * bar>;
 
-    Inspector& inspector = Build();
+@compute @workgroup_size(1i)
+fn ep() { _ = v[0]; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1071,22 +977,20 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideReferencedByArraySizeViaAlias) {
-    Override("foo", ty.u32());
-    Override("bar", ty.u32(), Expr("foo"));
-    Alias("MyArray", ty.array(ty.f32(), Mul(2_a, Expr("bar"))));
-    Override("zoo", ty.u32());
-    Alias("MyArrayUnused", ty.array(ty.f32(), Mul(2_a, Expr("zoo"))));
-    GlobalVar("v", core::AddressSpace::kWorkgroup, ty("MyArray"));
-    Func("ep", tint::Empty, ty.void_(),
-         Vector{
-             Assign(Phony(), IndexAccessor("v", 0_a)),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kCompute),
-             WorkgroupSize(1_i),
-         });
+    auto* src = R"(
+override foo: u32;
+override bar: u32 = foo;
+alias MyArray = array<f32, 2 * bar>;
 
-    Inspector& inspector = Build();
+override zoo: u32;
+alias MyArrayUnused = array<f32, 2 * zoo>;
+
+var<workgroup> v: MyArray;
+
+@compute @workgroup_size(1i)
+fn ep() { _ = v[0]; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1099,29 +1003,31 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideTypes) {
-    Enable(wgsl::Extension::kF16);
+    auto* src = R"(
+enable f16;
 
-    Override("bool_var", ty.bool_());
-    Override("float_var", ty.f32());
-    Override("u32_var", ty.u32());
-    Override("i32_var", ty.i32());
-    Override("f16_var", ty.f16());
+override bool_var: bool;
+override float_var: f32;
+override u32_var: u32;
+override i32_var: i32;
+override f16_var: f16;
 
-    MakePlainGlobalReferenceBodyFunction("bool_func", "bool_var", ty.bool_(), tint::Empty);
-    MakePlainGlobalReferenceBodyFunction("float_func", "float_var", ty.f32(), tint::Empty);
-    MakePlainGlobalReferenceBodyFunction("u32_func", "u32_var", ty.u32(), tint::Empty);
-    MakePlainGlobalReferenceBodyFunction("i32_func", "i32_var", ty.i32(), tint::Empty);
-    MakePlainGlobalReferenceBodyFunction("f16_func", "f16_var", ty.f16(), tint::Empty);
+fn bool_func() { _ = bool_var; }
+fn float_func() { _ = float_var; }
+fn u32_func() { _ = u32_var; }
+fn i32_func() { _ = i32_var; }
+fn f16_func() { _ = f16_var; }
 
-    MakeCallerBodyFunction(
-        "ep_func",
-        Vector{std::string("bool_func"), "float_func", "u32_func", "i32_func", "f16_func"},
-        Vector{
-            Stage(ast::PipelineStage::kCompute),
-            WorkgroupSize(1_i),
-        });
-
-    Inspector& inspector = Build();
+@compute @workgroup_size(1)
+fn ep_func() {
+  bool_func();
+  float_func();
+  u32_func();
+  i32_func();
+  f16_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1140,14 +1046,12 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideInitialized) {
-    Override("foo", ty.f32(), Expr(0_f));
-    MakePlainGlobalReferenceBodyFunction("ep_func", "foo", ty.f32(),
-                                         Vector{
-                                             Stage(ast::PipelineStage::kCompute),
-                                             WorkgroupSize(1_i),
-                                         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+override foo: f32 = 0f;
+@compute @workgroup_size(1i)
+fn ep_func() { _ = foo; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1158,14 +1062,12 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideUninitialized) {
-    Override("foo", ty.f32());
-    MakePlainGlobalReferenceBodyFunction("ep_func", "foo", ty.f32(),
-                                         Vector{
-                                             Stage(ast::PipelineStage::kCompute),
-                                             WorkgroupSize(1_i),
-                                         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+override foo: f32;
+@compute @workgroup_size(1i)
+fn ep_func() { _ = foo; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1177,19 +1079,20 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OverrideNumericIDSpecified) {
-    Override("foo_no_id", ty.f32());
-    Override("foo_id", ty.f32(), Id(1234_a));
+    auto* src = R"(
+override foo_no_id: f32;
+@id(1234) override foo_id: f32;
 
-    MakePlainGlobalReferenceBodyFunction("no_id_func", "foo_no_id", ty.f32(), tint::Empty);
-    MakePlainGlobalReferenceBodyFunction("id_func", "foo_id", ty.f32(), tint::Empty);
+fn no_id_func() { _ = foo_no_id; }
+fn id_func() { _ = foo_id; }
 
-    MakeCallerBodyFunction("ep_func", Vector{std::string("no_id_func"), "id_func"},
-                           Vector{
-                               Stage(ast::PipelineStage::kCompute),
-                               WorkgroupSize(1_i),
-                           });
-
-    Inspector& inspector = Build();
+@compute @workgroup_size(1i)
+fn ep_func() {
+  no_id_func();
+  id_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1204,20 +1107,19 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, NonOverrideSkipped) {
-    auto* foo_struct_type = MakeUniformBufferType("foo_type", Vector{
-                                                                  ty.i32(),
-                                                              });
-    AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
-    MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                            });
-    MakeCallerBodyFunction("ep_func", Vector{std::string("ub_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
+    auto* src = R"(
+struct foo_type {
+  a: i32,
+}
+@binding(0) @group(0) var<uniform> foo_ub: foo_type;
+fn ub_func() { _ = foo_ub.a; }
 
-    Inspector& inspector = Build();
+@fragment
+fn ep_func() {
+  ub_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1226,11 +1128,11 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, BuiltinNotReferenced) {
-    MakeEmptyBodyFunction("ep_func", Vector{
-                                         Stage(ast::PipelineStage::kFragment),
-                                     });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment
+fn ep_func() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1245,19 +1147,11 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, InputSampleMaskSimpleReferenced) {
-    auto* in_var = Param("in_var", ty.u32(),
-                         Vector{
-                             Builtin(core::BuiltinValue::kSampleMask),
-                         });
-    Func("ep_func", Vector{in_var}, ty.void_(),
-         Vector{
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment
+fn ep_func(@builtin(sample_mask) in_var: u32) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1266,25 +1160,15 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, InputSampleMaskStructReferenced) {
-    Vector members{
-        Member("inner_position", ty.u32(), Vector{Builtin(core::BuiltinValue::kSampleMask)}),
-    };
+    auto* src = R"(
+struct in_struct {
+  @builtin(sample_mask) inner_position: u32,
+}
 
-    Structure("in_struct", members);
-
-    Func("ep_func",
-         Vector{
-             Param("in_var", ty("in_struct"), tint::Empty),
-         },
-         ty.void_(),
-         Vector{
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+@fragment
+fn ep_func(in_var: in_struct) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1293,22 +1177,13 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OutputSampleMaskSimpleReferenced) {
-    Func("ep_func",
-         Vector{
-             Param("in_var", ty.u32(), Vector{Builtin(core::BuiltinValue::kSampleMask)}),
-         },
-         ty.u32(),
-         Vector{
-             Return("in_var"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         },
-         Vector{
-             Builtin(core::BuiltinValue::kSampleMask),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment
+fn ep_func(@builtin(sample_mask) in_var: u32) -> @builtin(sample_mask) u32 {
+  return in_var;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1317,21 +1192,18 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, OutputSampleMaskStructReferenced) {
-    Structure("out_struct", Vector{
-                                Member("inner_sample_mask", ty.u32(),
-                                       Vector{Builtin(core::BuiltinValue::kSampleMask)}),
-                            });
+    auto* src = R"(
+struct out_struct {
+  @builtin(sample_mask) inner_sample_mask: u32,
+}
 
-    Func("ep_func", tint::Empty, ty("out_struct"),
-         Vector{
-             Decl(Var("out_var", ty("out_struct"))),
-             Return("out_var"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+@fragment
+fn ep_func() -> out_struct {
+  var out_var: out_struct;
+  return out_var;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1340,19 +1212,11 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, InputPositionSimpleReferenced) {
-    Func("ep_func",
-         Vector{
-             Param("in_var", ty.vec4<f32>(), Vector{Builtin(core::BuiltinValue::kPosition)}),
-         },
-         ty.void_(),
-         Vector{
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment
+fn ep_func(@builtin(position) in_var: vec4f) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1361,24 +1225,14 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, InputPositionStructReferenced) {
-    Structure("in_struct", Vector{
-                               Member("inner_position", ty.vec4<f32>(),
-                                      Vector{Builtin(core::BuiltinValue::kPosition)}),
-                           });
-
-    Func("ep_func",
-         Vector{
-             Param("in_var", ty("in_struct"), tint::Empty),
-         },
-         ty.void_(),
-         Vector{
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct in_struct {
+  @builtin(position) inner_position: vec4f,
+}
+@fragment
+fn ep_func(in_var: in_struct) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1387,19 +1241,11 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, FrontFacingSimpleReferenced) {
-    Func("ep_func",
-         Vector{
-             Param("in_var", ty.bool_(), Vector{Builtin(core::BuiltinValue::kFrontFacing)}),
-         },
-         ty.void_(),
-         Vector{
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment
+fn ep_func(@builtin(front_facing) in_var: bool) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1408,24 +1254,14 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, FrontFacingStructReferenced) {
-    Structure("in_struct", Vector{
-                               Member("inner_position", ty.bool_(),
-                                      Vector{Builtin(core::BuiltinValue::kFrontFacing)}),
-                           });
-
-    Func("ep_func",
-         Vector{
-             Param("in_var", ty("in_struct"), tint::Empty),
-         },
-         ty.void_(),
-         Vector{
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct in_struct {
+  @builtin(front_facing) inner_position: bool,
+}
+@fragment
+fn ep_func(in_var: in_struct) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1434,19 +1270,11 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, SampleIndexSimpleReferenced) {
-    Func("ep_func",
-         Vector{
-             Param("in_var", ty.u32(), Vector{Builtin(core::BuiltinValue::kSampleIndex)}),
-         },
-         ty.void_(),
-         Vector{
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment
+fn ep_func(@builtin(sample_index) in_var: u32) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1455,24 +1283,15 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, SampleIndexStructReferenced) {
-    Structure("in_struct", Vector{
-                               Member("inner_position", ty.u32(),
-                                      Vector{Builtin(core::BuiltinValue::kSampleIndex)}),
-                           });
+    auto* src = R"(
+struct in_struct {
+  @builtin(sample_index) inner_position: u32,
+}
 
-    Func("ep_func",
-         Vector{
-             Param("in_var", ty("in_struct"), tint::Empty),
-         },
-         ty.void_(),
-         Vector{
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+@fragment
+fn ep_func(in_var: in_struct) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1481,17 +1300,11 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, NumWorkgroupsSimpleReferenced) {
-    Func("ep_func",
-         Vector{
-             Param("in_var", ty.vec3<u32>(), Vector{Builtin(core::BuiltinValue::kNumWorkgroups)}),
-         },
-         ty.void_(),
-         Vector{
-             Return(),
-         },
-         Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)}, tint::Empty);
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@compute @workgroup_size(1i)
+fn ep_func(@builtin(num_workgroups) in_var: vec3u) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1500,22 +1313,15 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, NumWorkgroupsStructReferenced) {
-    Structure("in_struct", Vector{
-                               Member("inner_position", ty.vec3<u32>(),
-                                      Vector{Builtin(core::BuiltinValue::kNumWorkgroups)}),
-                           });
+    auto* src = R"(
+struct in_struct {
+  @builtin(num_workgroups) inner_position: vec3u,
+}
 
-    Func("ep_func",
-         Vector{
-             Param("in_var", ty("in_struct"), tint::Empty),
-         },
-         ty.void_(),
-         Vector{
-             Return(),
-         },
-         Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)}, tint::Empty);
-
-    Inspector& inspector = Build();
+@compute @workgroup_size(1i)
+fn ep_func(in_var: in_struct) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1524,18 +1330,13 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, FragDepthSimpleReferenced) {
-    Func("ep_func", {}, ty.f32(),
-         Vector{
-             Return(Expr(0_f)),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         },
-         Vector{
-             Builtin(core::BuiltinValue::kFragDepth),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment
+fn ep_func() -> @builtin(frag_depth) f32 {
+  return 0f;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1544,21 +1345,17 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, FragDepthStructReferenced) {
-    Structure("out_struct", Vector{
-                                Member("inner_frag_depth", ty.f32(),
-                                       Vector{Builtin(core::BuiltinValue::kFragDepth)}),
-                            });
-
-    Func("ep_func", tint::Empty, ty("out_struct"),
-         Vector{
-             Decl(Var("out_var", ty("out_struct"))),
-             Return("out_var"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct out_struct {
+  @builtin(frag_depth) inner_frag_depth: f32,
+}
+@fragment
+fn ep_func() -> out_struct {
+  var out_var: out_struct;
+  return out_var;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1567,22 +1364,21 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, ClipDistancesReferenced) {
-    Enable(wgsl::Extension::kClipDistances);
+    auto* src = R"(
+enable clip_distances;
 
-    Structure("out_struct", Vector{Member("inner_clip_distances", ty.array<f32, 8>(),
-                                          Vector{Builtin(core::BuiltinValue::kClipDistances)}),
-                                   Member("inner_position", ty.vec4<f32>(),
-                                          Vector{Builtin(core::BuiltinValue::kPosition)})});
-    Func("ep_func", tint::Empty, ty("out_struct"),
-         Vector{
-             Decl(Var("out_var", ty("out_struct"))),
-             Return("out_var"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kVertex),
-         });
+struct out_struct {
+  @builtin(clip_distances) inner_clip_distances: array<f32, 8>,
+  @builtin(position) inner_position: vec4f,
+}
 
-    Inspector& inspector = Build();
+@vertex
+fn ep_func() -> out_struct {
+  var out_var: out_struct;
+  return out_var;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1592,18 +1388,17 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, ClipDistancesNotReferenced) {
-    Structure("out_struct", Vector{Member("inner_position", ty.vec4<f32>(),
-                                          Vector{Builtin(core::BuiltinValue::kPosition)})});
-    Func("ep_func", tint::Empty, ty("out_struct"),
-         Vector{
-             Decl(Var("out_var", ty("out_struct"))),
-             Return("out_var"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kVertex),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct out_struct {
+  @builtin(position) inner_position: vec4f,
+}
+@vertex
+fn ep_func() -> out_struct {
+  var out_var : out_struct;
+  return out_var;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1612,23 +1407,14 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, ImplicitInterpolate) {
-    Structure("in_struct", Vector{
-                               Member("struct_inner", ty.f32(), Vector{Location(0_a)}),
-                           });
-
-    Func("ep_func",
-         Vector{
-             Param("in_var", ty("in_struct"), tint::Empty),
-         },
-         ty.void_(),
-         Vector{
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct in_struct {
+  @location(0) struct_inner: f32,
+}
+@fragment
+fn ep_func(in_var: in_struct) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1639,12 +1425,11 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, PixelLocalMemberDefault) {
-    // @fragment fn foo() {}
-    MakeEmptyBodyFunction("foo", Vector{
-                                     Stage(ast::PipelineStage::kFragment),
-                                 });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment
+fn foo() {}
+)";
+    Inspector& inspector = Initialize(src);
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
@@ -1653,33 +1438,20 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, PixelLocalMemberTypes) {
-    // enable chromium_experimental_pixel_local;
-    // struct Ure {
-    //   toto : u32;
-    //   titi : f32;
-    //   tata: i32;
-    //   tonton : u32; // Check having the same type multiple times
-    // }
-    // var<pixel_local> pls : Ure;
-    // @fragment fn foo() {  _ = pls; }
+    auto* src = R"(
+enable chromium_experimental_pixel_local;
 
-    Enable(wgsl::Extension::kChromiumExperimentalPixelLocal);
-    Structure("Ure", Vector{
-                         Member("toto", ty.u32()),
-                         Member("titi", ty.f32()),
-                         Member("tata", ty.i32()),
-                         Member("tonton", ty.u32()),
-                     });
-    GlobalVar("pls", core::AddressSpace::kPixelLocal, ty("Ure"));
-    Func("foo", tint::Empty, ty.void_(),
-         Vector{
-             Assign(Phony(), "pls"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
+struct Ure {
+  toto: u32,
+  titi: f32,
+  tata: i32,
+  tonton: u32, // Check having the same type multiple times
+}
 
-    Inspector& inspector = Build();
+var<pixel_local> pls: Ure;
+@fragment fn foo() {  _ = pls; }
+)";
+    Inspector& inspector = Initialize(src);
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
@@ -1691,27 +1463,24 @@
     ASSERT_EQ(PixelLocalMemberType::kU32, result[0].pixel_local_members[3]);
 }
 
+struct InspectorGetEntryPointInterpolateTestParams {
+    std::string in;
+    inspector::InterpolationType out_type;
+    inspector::InterpolationSampling out_sampling;
+};
+using InspectorGetEntryPointInterpolateTest =
+    InspectorTestWithParam<InspectorGetEntryPointInterpolateTestParams>;
+
 TEST_P(InspectorGetEntryPointInterpolateTest, Test) {
     auto& params = GetParam();
-    Structure("in_struct",
-              Vector{
-                  Member("struct_inner", ty.f32(),
-                         Vector{Interpolate(params.in_type, params.in_sampling), Location(0_a)}),
-              });
-
-    Func("ep_func",
-         Vector{
-             Param("in_var", ty("in_struct"), tint::Empty),
-         },
-         ty.void_(),
-         Vector{
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto src = R"(
+struct in_struct {
+  )" + params.in +
+               R"( @location(0) struct_inner: f32,
+}
+@fragment fn ep_func(in_var: in_struct) {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -1725,64 +1494,59 @@
     InspectorGetEntryPointTest,
     InspectorGetEntryPointInterpolateTest,
     testing::Values(
+        InspectorGetEntryPointInterpolateTestParams{"@interpolate(perspective, center)",
+                                                    InterpolationType::kPerspective,
+                                                    InterpolationSampling::kCenter},
+        InspectorGetEntryPointInterpolateTestParams{"@interpolate(perspective, centroid)",
+                                                    InterpolationType::kPerspective,
+                                                    InterpolationSampling::kCentroid},
+        InspectorGetEntryPointInterpolateTestParams{"@interpolate(perspective, sample)",
+                                                    InterpolationType::kPerspective,
+                                                    InterpolationSampling::kSample},
+        InspectorGetEntryPointInterpolateTestParams{"@interpolate(perspective)",
+                                                    InterpolationType::kPerspective,
+                                                    InterpolationSampling::kCenter},
+        InspectorGetEntryPointInterpolateTestParams{"@interpolate(linear, center)",
+                                                    InterpolationType::kLinear,
+                                                    InterpolationSampling::kCenter},
+        InspectorGetEntryPointInterpolateTestParams{"@interpolate(linear, centroid)",
+                                                    InterpolationType::kLinear,
+                                                    InterpolationSampling::kCentroid},
+        InspectorGetEntryPointInterpolateTestParams{"@interpolate(linear, sample)",
+                                                    InterpolationType::kLinear,
+                                                    InterpolationSampling::kSample},
         InspectorGetEntryPointInterpolateTestParams{
-            core::InterpolationType::kPerspective, core::InterpolationSampling::kCenter,
-            InterpolationType::kPerspective, InterpolationSampling::kCenter},
+            "@interpolate(linear)", InterpolationType::kLinear, InterpolationSampling::kCenter},
+        InspectorGetEntryPointInterpolateTestParams{"@interpolate(flat)", InterpolationType::kFlat,
+                                                    InterpolationSampling::kFirst},
         InspectorGetEntryPointInterpolateTestParams{
-            core::InterpolationType::kPerspective, core::InterpolationSampling::kCentroid,
-            InterpolationType::kPerspective, InterpolationSampling::kCentroid},
-        InspectorGetEntryPointInterpolateTestParams{
-            core::InterpolationType::kPerspective, core::InterpolationSampling::kSample,
-            InterpolationType::kPerspective, InterpolationSampling::kSample},
-        InspectorGetEntryPointInterpolateTestParams{
-            core::InterpolationType::kPerspective, core::InterpolationSampling::kUndefined,
-            InterpolationType::kPerspective, InterpolationSampling::kCenter},
-        InspectorGetEntryPointInterpolateTestParams{
-            core::InterpolationType::kLinear, core::InterpolationSampling::kCenter,
-            InterpolationType::kLinear, InterpolationSampling::kCenter},
-        InspectorGetEntryPointInterpolateTestParams{
-            core::InterpolationType::kLinear, core::InterpolationSampling::kCentroid,
-            InterpolationType::kLinear, InterpolationSampling::kCentroid},
-        InspectorGetEntryPointInterpolateTestParams{
-            core::InterpolationType::kLinear, core::InterpolationSampling::kSample,
-            InterpolationType::kLinear, InterpolationSampling::kSample},
-        InspectorGetEntryPointInterpolateTestParams{
-            core::InterpolationType::kLinear, core::InterpolationSampling::kUndefined,
-            InterpolationType::kLinear, InterpolationSampling::kCenter},
-        InspectorGetEntryPointInterpolateTestParams{
-            core::InterpolationType::kFlat, core::InterpolationSampling::kUndefined,
-            InterpolationType::kFlat, InterpolationSampling::kFirst},
-        InspectorGetEntryPointInterpolateTestParams{
-            core::InterpolationType::kFlat, core::InterpolationSampling::kFirst,
-            InterpolationType::kFlat, InterpolationSampling::kFirst},
-        InspectorGetEntryPointInterpolateTestParams{
-            core::InterpolationType::kFlat, core::InterpolationSampling::kEither,
-            InterpolationType::kFlat, InterpolationSampling::kEither}));
+            "@interpolate(flat, first)", InterpolationType::kFlat, InterpolationSampling::kFirst},
+        InspectorGetEntryPointInterpolateTestParams{"@interpolate(flat, either)",
+                                                    InterpolationType::kFlat,
+                                                    InterpolationSampling::kEither}));
 
 TEST_F(InspectorOverridesTest, NoOverrides) {
-    MakeCallerBodyFunction("ep_func", Empty,
-                           Vector{
-                               Stage(ast::PipelineStage::kCompute),
-                               WorkgroupSize(1_i),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@compute @workgroup_size(1i)
+fn ep_func() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.Overrides();
     EXPECT_TRUE(result.empty());
 }
 
 TEST_F(InspectorOverridesTest, Multiple) {
-    Override("foo", ty.f32(), Id(1_a));
-    Override("bar", ty.f32(), Id(2_a));
-    MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), tint::Empty);
-    MakeCallerBodyFunction("ep_func", Vector{std::string("callee_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kCompute),
-                               WorkgroupSize(1_i),
-                           });
+    auto* src = R"(
+@id(1) override foo: f32;
+@id(2) override bar: f32;
 
-    Inspector& inspector = Build();
+fn callee_func() { _ = foo; }
+@compute @workgroup_size(1i) fn ep_func() {
+  callee_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.Overrides();
     ASSERT_EQ(2u, result.size());
@@ -1901,14 +1665,15 @@
 }
 
 TEST_F(InspectorGetOverrideDefaultValuesTest, Bool) {
-    GlobalConst("C", Expr(true));
-    Override("a", ty.bool_(), Id(1_a));
-    Override("b", ty.bool_(), Expr(true), Id(20_a));
-    Override("c", Expr(false), Id(300_a));
-    Override("d", Or(true, false), Id(400_a));
-    Override("e", Expr("C"), Id(500_a));
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+const C = true;
+@id(1) override a: bool;
+@id(20) override b: bool = true;
+@id(300) override c = false;
+@id(400) override d = true || false;
+@id(500) override e = C;
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetOverrideDefaultValues();
     ASSERT_EQ(5u, result.size());
@@ -1934,15 +1699,16 @@
 }
 
 TEST_F(InspectorGetOverrideDefaultValuesTest, U32) {
-    GlobalConst("C", Expr(100_u));
-    Override("a", ty.u32(), Id(1_a));
-    Override("b", ty.u32(), Expr(42_u), Id(20_a));
-    Override("c", ty.u32(), Expr(42_a), Id(30_a));
-    Override("d", ty.u32(), Add(42_a, 10_a), Id(40_a));
-    Override("e", Add(42_a, 10_u), Id(50_a));
-    Override("f", Expr("C"), Id(60_a));
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+const C = 100u;
+@id(1) override a: u32;
+@id(20) override b: u32 = 42u;
+@id(30) override c: u32 = 42;
+@id(40) override d: u32 = 42 + 10;
+@id(50) override e = 42 + 10u;
+@id(60) override f = C;
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetOverrideDefaultValues();
     ASSERT_EQ(6u, result.size());
@@ -1972,15 +1738,16 @@
 }
 
 TEST_F(InspectorGetOverrideDefaultValuesTest, I32) {
-    GlobalConst("C", Expr(100_a));
-    Override("a", ty.i32(), Id(1_a));
-    Override("b", ty.i32(), Expr(-42_i), Id(20_a));
-    Override("c", ty.i32(), Expr(42_i), Id(300_a));
-    Override("d", Expr(42_a), Id(400_a));
-    Override("e", Add(42_a, 7_a), Id(500_a));
-    Override("f", Expr("C"), Id(6000_a));
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+const C = 100;
+@id(1) override a: i32;
+@id(20) override b: i32 = -42i;
+@id(300) override c: i32 = 42i;
+@id(400) override d = 42;
+@id(500) override e = 42 + 7;
+@id(6000) override f = C;
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetOverrideDefaultValues();
     ASSERT_EQ(6u, result.size());
@@ -2010,14 +1777,15 @@
 }
 
 TEST_F(InspectorGetOverrideDefaultValuesTest, F32) {
-    Override("a", ty.f32(), Id(1_a));
-    Override("b", ty.f32(), Expr(0_f), Id(20_a));
-    Override("c", ty.f32(), Expr(-10_f), Id(300_a));
-    Override("d", Expr(15_f), Id(4000_a));
-    Override("3", Expr(42.0_a), Id(5000_a));
-    Override("e", ty.f32(), Mul(15_f, 10_a), Id(6000_a));
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@id(1) override a: f32;
+@id(20) override b: f32 = 0f;
+@id(300) override c: f32 = -10f;
+@id(4000) override d = 15f;
+@id(5000) override e = 42.0;
+@id(6000) override f: f32 = 15f * 10;
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetOverrideDefaultValues();
     ASSERT_EQ(6u, result.size());
@@ -2047,16 +1815,17 @@
 }
 
 TEST_F(InspectorGetOverrideDefaultValuesTest, F16) {
-    Enable(wgsl::Extension::kF16);
+    auto* src = R"(
+enable f16;
 
-    Override("a", ty.f16(), Id(1_a));
-    Override("b", ty.f16(), Expr(0_h), Id(20_a));
-    Override("c", ty.f16(), Expr(-10_h), Id(300_a));
-    Override("d", Expr(15_h), Id(4000_a));
-    Override("3", Expr(42.0_h), Id(5000_a));
-    Override("e", ty.f16(), Mul(15_h, 10_a), Id(6000_a));
-
-    Inspector& inspector = Build();
+@id(1) override a: f16;
+@id(20) override b: f16 = 0h;
+@id(300) override c: f16 = -10h;
+@id(4000) override d = 15h;
+@id(5000) override e = 42.0h;
+@id(6000) override f: f16 = 15h * 10;
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetOverrideDefaultValues();
     ASSERT_EQ(6u, result.size());
@@ -2087,14 +1856,15 @@
 }
 
 TEST_F(InspectorGetConstantNameToIdMapTest, WithAndWithoutIds) {
-    Override("v1", ty.f32(), Id(1_a));
-    Override("v20", ty.f32(), Id(20_a));
-    Override("v300", ty.f32(), Id(300_a));
-    auto* a = Override("a", ty.f32());
-    auto* b = Override("b", ty.f32());
-    auto* c = Override("c", ty.f32());
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@id(1) override v1: f32;
+@id(20) override v20: f32;
+@id(300) override v300: f32;
+override a: f32;
+override b: f32;
+override c: f32;
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetNamedOverrideIds();
     ASSERT_EQ(6u, result.size());
@@ -2109,25 +1879,20 @@
     EXPECT_EQ(result["v300"].value, 300u);
 
     ASSERT_TRUE(result.count("a"));
-    ASSERT_TRUE(program_->Sem().Get(a));
-    EXPECT_EQ(result["a"], program_->Sem().Get(a)->Attributes().override_id);
+    EXPECT_EQ(result["a"].value, 0);
 
     ASSERT_TRUE(result.count("b"));
-    ASSERT_TRUE(program_->Sem().Get(b));
-    EXPECT_EQ(result["b"], program_->Sem().Get(b)->Attributes().override_id);
+    EXPECT_EQ(result["b"].value, 2);
 
     ASSERT_TRUE(result.count("c"));
-    ASSERT_TRUE(program_->Sem().Get(c));
-    EXPECT_EQ(result["c"], program_->Sem().Get(c)->Attributes().override_id);
+    EXPECT_EQ(result["c"].value, 3);
 }
 
 TEST_F(InspectorGetResourceBindingsTest, Empty) {
-    MakeCallerBodyFunction("ep_func", tint::Empty,
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@fragment fn ep_func() {}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2135,75 +1900,60 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, Simple) {
-    auto* ub_struct_type = MakeUniformBufferType("ub_type", Vector{
-                                                                ty.i32(),
-                                                            });
-    AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
-    MakeStructVariableReferenceBodyFunction("ub_func", "ub_var",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                            });
+    auto* src = R"(
+struct ub_type {
+  a: i32,
+}
+@group(0) @binding(0) var<uniform> ub_var: ub_type;
+fn ub_func() { _ = ub_var.a; }
 
-    auto sb = MakeStorageBufferTypes("sb_type", Vector{
-                                                    ty.i32(),
-                                                });
-    AddStorageBuffer("sb_var", sb(), core::Access::kReadWrite, 1, 0);
-    MakeStructVariableReferenceBodyFunction("sb_func", "sb_var",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                            });
+struct sb_type {
+  a: i32,
+}
+@group(1) @binding(0) var<storage, read_write> sb_var: sb_type;
+fn sb_func() { _ = sb_var.a; }
 
-    auto ro_sb = MakeStorageBufferTypes("rosb_type", Vector{
-                                                         ty.i32(),
-                                                     });
-    AddStorageBuffer("rosb_var", ro_sb(), core::Access::kRead, 1, 1);
-    MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                            });
+struct rosb_type {
+  a: i32,
+}
+@group(1) @binding(1) var<storage, read> rosb_var: rosb_type;
+fn rosb_func() { _ = rosb_var.a; }
 
-    auto s_texture_type = ty.sampled_texture(core::type::TextureDimension::k1d, ty.f32());
-    AddResource("s_texture", s_texture_type, 2, 0);
-    AddSampler("s_var", 3, 0);
-    AddGlobalVariable("s_coords", ty.f32());
-    MakeSamplerReferenceBodyFunction("s_func", "s_texture", "s_var", "s_coords", ty.f32(),
-                                     tint::Empty);
+@group(2) @binding(0) var s_texture : texture_1d<f32>;
+@group(3) @binding(0) var s_var: sampler;
+var<private> s_coords: f32;
+fn s_func() {
+  let sampler_result = textureSample(s_texture, s_var, s_coords);
+}
 
-    auto cs_depth_texture_type = ty.depth_texture(core::type::TextureDimension::k2d);
-    AddResource("cs_texture", cs_depth_texture_type, 3, 1);
-    AddComparisonSampler("cs_var", 3, 2);
-    AddGlobalVariable("cs_coords", ty.vec2<f32>());
-    AddGlobalVariable("cs_depth", ty.f32());
-    MakeComparisonSamplerReferenceBodyFunction("cs_func", "cs_texture", "cs_var", "cs_coords",
-                                               "cs_depth", ty.f32(), tint::Empty);
+@group(3) @binding(1) var cs_texture : texture_depth_2d;
+@group(3) @binding(2) var cs_var: sampler_comparison;
+var<private> cs_coords: vec2f;
+var<private> cs_depth: f32;
+fn cs_func() {
+  let sampler_result = textureSampleCompare(cs_texture, cs_var, cs_coords, cs_depth);
+}
 
-    auto depth_ms_texture_type = ty.depth_multisampled_texture(core::type::TextureDimension::k2d);
-    AddResource("depth_ms_texture", depth_ms_texture_type, 3, 3);
-    Func("depth_ms_func", tint::Empty, ty.void_(),
-         Vector{
-             Ignore("depth_ms_texture"),
-         });
+@group(3) @binding(3) var depth_ms_texture : texture_depth_multisampled_2d;
+fn depth_ms_func() {
+  _ = depth_ms_texture;
+}
 
-    auto st_type = MakeStorageTextureTypes(core::type::TextureDimension::k2d,
-                                           core::TexelFormat::kR32Uint, core::Access::kWrite);
-    AddStorageTexture("st_var", st_type, 4, 0);
-    MakeStorageTextureBodyFunction("st_func", "st_var", ty.vec2<u32>(), tint::Empty);
+@group(4) @binding(0) var st_var: texture_storage_2d<r32uint, write>;
+fn st_func() { let dim = textureDimensions(st_var); }
 
-    MakeCallerBodyFunction("ep_func",
-                           Vector{
-                               std::string("ub_func"),
-                               std::string("sb_func"),
-                               std::string("rosb_func"),
-                               std::string("s_func"),
-                               std::string("cs_func"),
-                               std::string("depth_ms_func"),
-                               std::string("st_func"),
-                           },
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+@fragment
+fn ep_func() {
+  ub_func();
+  sb_func();
+  rosb_func();
+  s_func();
+  cs_func();
+  depth_ms_func();
+  st_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2247,47 +1997,22 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, InputAttachment) {
-    // enable chromium_internal_input_attachments;
-    // @group(0) @binding(1) @input_attachment_index(3)
-    // var input_tex1 : input_attachment<f32>;
-    //
-    // @group(4) @binding(3) @input_attachment_index(1)
-    // var input_tex2 : input_attachment<i32>;
-    //
-    // fn f1() -> vec4f {
-    //    return inputAttachmentLoad(input_tex1);
-    // }
-    //
-    // fn f2() -> vec4i {
-    //    return inputAttachmentLoad(input_tex2);
-    // }
+    auto* src = R"(
+enable chromium_internal_input_attachments;
 
-    Enable(Source{{12, 34}}, wgsl::Extension::kChromiumInternalInputAttachments);
+@group(0) @binding(1) @input_attachment_index(3) var input_tex1: input_attachment<f32>;
+@group(4) @binding(3) @input_attachment_index(1) var input_tex2: input_attachment<i32>;
 
-    GlobalVar("input_tex1", ty.input_attachment(ty.Of<f32>()),
-              Vector{Group(0_u), Binding(1_u), InputAttachmentIndex(3_u)});
-    GlobalVar("input_tex2", ty.input_attachment(ty.Of<i32>()),
-              Vector{Group(4_u), Binding(3_u), InputAttachmentIndex(1_u)});
+fn f1() -> vec4f { return inputAttachmentLoad(input_tex1); }
+fn f2() -> vec4i { return inputAttachmentLoad(input_tex2); }
 
-    Func("f1", Empty, ty.vec4<f32>(),
-         Vector{
-             Return(Call("inputAttachmentLoad", "input_tex1")),
-         });
-    Func("f2", Empty, ty.vec4<i32>(),
-         Vector{
-             Return(Call("inputAttachmentLoad", "input_tex2")),
-         });
-
-    MakeCallerBodyFunction("main",
-                           Vector{
-                               std::string("f1"),
-                               std::string("f2"),
-                           },
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+@fragment
+fn main() {
+  f1();
+  f2();
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("main");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2307,7 +2032,8 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, MissingEntryPoint) {
-    Inspector& inspector = Build();
+    auto* src = R"()";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_TRUE(inspector.has_error());
@@ -2316,22 +2042,16 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, NonEntryPointFunc) {
-    auto* foo_struct_type = MakeUniformBufferType("foo_type", Vector{
-                                                                  ty.i32(),
-                                                              });
-    AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
+    auto* src = R"(
+struct foo_type {
+  a: i32,
+}
+@group(0) @binding(0) var<uniform> foo_ub: foo_type;
+fn ub_func() { _ = foo_ub.a; }
 
-    MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                            });
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("ub_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+@fragment fn ep_func() { ub_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ub_func");
     std::string error = inspector.error();
@@ -2339,15 +2059,12 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, UniformBuffer_Simple_NonStruct) {
-    AddUniformBuffer("foo_ub", ty.i32(), 0, 0);
-    MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.i32(), tint::Empty);
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("ub_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> foo_ub: i32;
+fn ub_func() { _ = foo_ub; }
+@fragment fn ep_func() { ub_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2361,23 +2078,15 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, UniformBuffer_Simple_Struct) {
-    auto* foo_struct_type = MakeUniformBufferType("foo_type", Vector{
-                                                                  ty.i32(),
-                                                              });
-    AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
-
-    MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                            });
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("ub_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
-
+    auto* src = R"(
+struct foo_type {
+  a: i32,
+}
+@group(0) @binding(0) var<uniform> foo_ub: foo_type;
+fn ub_func() { _ = foo_ub.a; }
+@fragment fn ep_func() { ub_func(); }
+)";
+    Inspector& inspector = Initialize(src);
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
     ASSERT_EQ(1u, result.size());
@@ -2390,26 +2099,21 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, UniformBuffer_MultipleMembers) {
-    auto* foo_struct_type = MakeUniformBufferType("foo_type", Vector{
-                                                                  ty.i32(),
-                                                                  ty.u32(),
-                                                                  ty.f32(),
-                                                              });
-    AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
-
-    MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                                MemberInfo{1, ty.u32()},
-                                                MemberInfo{2, ty.f32()},
-                                            });
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("ub_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct foo_type {
+  a: i32,
+  b: u32,
+  c: f32,
+}
+@group(0) @binding(0) var<uniform> foo_ub: foo_type;
+fn ub_func() {
+  _ = foo_ub.a;
+  _ = foo_ub.b;
+  _ = foo_ub.c;
+}
+@fragment fn ep_func() { ub_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2423,22 +2127,15 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, UniformBuffer_ContainingPadding) {
-    auto* foo_struct_type = MakeUniformBufferType("foo_type", Vector{
-                                                                  ty.vec3<f32>(),
-                                                              });
-    AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
-
-    MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
-                                            Vector{
-                                                MemberInfo{0, ty.vec3<f32>()},
-                                            });
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("ub_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct foo_type {
+  a: vec3f,
+}
+@group(0) @binding(0) var<uniform> foo_ub: foo_type;
+fn ub_func() { _ = foo_ub.a; }
+@fragment fn ep_func() { ub_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2452,15 +2149,12 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, UniformBuffer_NonStructVec3) {
-    AddUniformBuffer("foo_ub", ty.vec3<f32>(), 0, 0);
-    MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.vec3<f32>(), tint::Empty);
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("ub_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@group(0) @binding(0) var<uniform> foo_ub: vec3f;
+fn ub_func() { _ = foo_ub; }
+@fragment fn ep_func() { ub_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2474,41 +2168,26 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, UniformBuffer_Multiple) {
-    auto* ub_struct_type = MakeUniformBufferType("ub_type", Vector{
-                                                                ty.i32(),
-                                                                ty.u32(),
-                                                                ty.f32(),
-                                                            });
-    AddUniformBuffer("ub_foo", ty.Of(ub_struct_type), 0, 0);
-    AddUniformBuffer("ub_bar", ty.Of(ub_struct_type), 0, 1);
-    AddUniformBuffer("ub_baz", ty.Of(ub_struct_type), 2, 0);
+    auto* src = R"(
+struct ub_type {
+  a: i32,
+  b: u32,
+  c: f32,
+}
+@group(0) @binding(0) var<uniform> ub_foo: ub_type;
+@group(0) @binding(1) var<uniform> ub_bar: ub_type;
+@group(2) @binding(0) var<uniform> ub_baz: ub_type;
+fn ub_foo_func() { _ = ub_foo.a; _ = ub_foo.b; _ = ub_foo.c; }
+fn ub_bar_func() { _ = ub_bar.a; _ = ub_bar.b; _ = ub_bar.c; }
+fn ub_baz_func() { _ = ub_baz.a; _ = ub_baz.b; _ = ub_baz.c; }
 
-    auto AddReferenceFunc = [this](const std::string& func_name, const std::string& var_name) {
-        MakeStructVariableReferenceBodyFunction(func_name, var_name,
-                                                Vector{
-                                                    MemberInfo{0, ty.i32()},
-                                                    MemberInfo{1, ty.u32()},
-                                                    MemberInfo{2, ty.f32()},
-                                                });
-    };
-    AddReferenceFunc("ub_foo_func", "ub_foo");
-    AddReferenceFunc("ub_bar_func", "ub_bar");
-    AddReferenceFunc("ub_baz_func", "ub_baz");
-
-    auto FuncCall = [&](const std::string& callee) { return CallStmt(Call(callee)); };
-
-    Func("ep_func", tint::Empty, ty.void_(),
-         Vector{
-             FuncCall("ub_foo_func"),
-             FuncCall("ub_bar_func"),
-             FuncCall("ub_baz_func"),
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+@fragment fn ep_func() {
+  ub_foo_func();
+  ub_bar_func();
+  ub_baz_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2536,30 +2215,16 @@
 TEST_F(InspectorGetResourceBindingsTest, UniformBuffer_ContainingArray) {
     // Manually create uniform buffer to make sure it had a valid layout (array
     // with elem stride of 16, and that is 16-byte aligned within the struct)
-    auto* foo_struct_type = Structure("foo_type", Vector{
-                                                      Member("0i32", ty.i32()),
-                                                      Member("b",
-                                                             ty.array<u32, 4>(Vector{
-                                                                 Stride(16),
-                                                             }),
-                                                             Vector{
-                                                                 MemberAlign(16_i),
-                                                             }),
-                                                  });
-
-    AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
-
-    MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                            });
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("ub_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct foo_type {
+  a: i32,
+  @align(16) b: array<vec4i, 4>,
+}
+@group(0) @binding(0) var<uniform> foo_ub: foo_type;
+fn ub_func() { _ = foo_ub.a; }
+@fragment fn ep_func() { ub_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2573,15 +2238,12 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, StorageBuffer_Simple_NonStruct) {
-    AddStorageBuffer("foo_sb", ty.i32(), core::Access::kReadWrite, 0, 0);
-    MakePlainGlobalReferenceBodyFunction("sb_func", "foo_sb", ty.i32(), tint::Empty);
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("sb_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> foo_sb: i32;
+fn sb_func() { _ = foo_sb; }
+@fragment fn ep_func() { sb_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2595,22 +2257,15 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, StorageBuffer_Simple_Struct) {
-    auto foo_struct_type = MakeStorageBufferTypes("foo_type", Vector{
-                                                                  ty.i32(),
-                                                              });
-    AddStorageBuffer("foo_sb", foo_struct_type(), core::Access::kReadWrite, 0, 0);
-
-    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                            });
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("sb_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct foo_type {
+  a: i32,
+}
+@group(0) @binding(0) var<storage, read_write> foo_sb: foo_type;
+fn sb_func() { _ = foo_sb.a; }
+@fragment fn ep_func() { sb_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2624,26 +2279,17 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, StorageBuffer_MultipleMembers) {
-    auto foo_struct_type = MakeStorageBufferTypes("foo_type", Vector{
-                                                                  ty.i32(),
-                                                                  ty.u32(),
-                                                                  ty.f32(),
-                                                              });
-    AddStorageBuffer("foo_sb", foo_struct_type(), core::Access::kReadWrite, 0, 0);
-
-    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                                MemberInfo{1, ty.u32()},
-                                                MemberInfo{2, ty.f32()},
-                                            });
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("sb_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct foo_type {
+  a: i32,
+  b: u32,
+  c: f32
+}
+@group(0) @binding(0) var<storage, read_write> foo_sb: foo_type;
+fn sb_func() { _ = foo_sb.a; _ = foo_sb.b; _ = foo_sb.c; }
+@fragment fn ep_func() { sb_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2657,41 +2303,27 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, StorageBuffer_Multiple) {
-    auto sb_struct_type = MakeStorageBufferTypes("sb_type", Vector{
-                                                                ty.i32(),
-                                                                ty.u32(),
-                                                                ty.f32(),
-                                                            });
-    AddStorageBuffer("sb_foo", sb_struct_type(), core::Access::kReadWrite, 0, 0);
-    AddStorageBuffer("sb_bar", sb_struct_type(), core::Access::kReadWrite, 0, 1);
-    AddStorageBuffer("sb_baz", sb_struct_type(), core::Access::kReadWrite, 2, 0);
+    auto* src = R"(
+struct sb_type {
+  a: i32,
+  b: u32,
+  c: f32,
+}
+@group(0) @binding(0) var<storage, read_write> sb_foo: sb_type;
+@group(0) @binding(1) var<storage, read_write> sb_bar: sb_type;
+@group(2) @binding(0) var<storage, read_write> sb_baz: sb_type;
+fn sb_foo_func() { _ = sb_foo.a; _ = sb_foo.b; _ = sb_foo.c; }
+fn sb_bar_func() { _ = sb_bar.a; _ = sb_bar.b; _ = sb_bar.c; }
+fn sb_baz_func() { _ = sb_baz.a; _ = sb_baz.b; _ = sb_baz.c; }
 
-    auto AddReferenceFunc = [this](const std::string& func_name, const std::string& var_name) {
-        MakeStructVariableReferenceBodyFunction(func_name, var_name,
-                                                Vector{
-                                                    MemberInfo{0, ty.i32()},
-                                                    MemberInfo{1, ty.u32()},
-                                                    MemberInfo{2, ty.f32()},
-                                                });
-    };
-    AddReferenceFunc("sb_foo_func", "sb_foo");
-    AddReferenceFunc("sb_bar_func", "sb_bar");
-    AddReferenceFunc("sb_baz_func", "sb_baz");
-
-    auto FuncCall = [&](const std::string& callee) { return CallStmt(Call(callee)); };
-
-    Func("ep_func", tint::Empty, ty.void_(),
-         Vector{
-             FuncCall("sb_foo_func"),
-             FuncCall("sb_bar_func"),
-             FuncCall("sb_baz_func"),
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+@fragment
+fn ep_func() {
+  sb_foo_func();
+  sb_bar_func();
+  sb_baz_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2717,23 +2349,16 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, StorageBuffer_ContainingArray) {
-    auto foo_struct_type = MakeStorageBufferTypes("foo_type", Vector{
-                                                                  ty.i32(),
-                                                                  ty.array<u32, 4>(),
-                                                              });
-    AddStorageBuffer("foo_sb", foo_struct_type(), core::Access::kReadWrite, 0, 0);
-
-    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                            });
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("sb_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct foo_type {
+  a: i32,
+  b: array<u32, 4>,
+}
+@group(0) @binding(0) var<storage, read_write> foo_sb: foo_type;
+fn sb_func() { _ = foo_sb.a; }
+@fragment fn ep_func() { sb_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2747,23 +2372,16 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, StorageBuffer_ContainingRuntimeArray) {
-    auto foo_struct_type = MakeStorageBufferTypes("foo_type", Vector{
-                                                                  ty.i32(),
-                                                                  ty.array<u32>(),
-                                                              });
-    AddStorageBuffer("foo_sb", foo_struct_type(), core::Access::kReadWrite, 0, 0);
-
-    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                            });
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("sb_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct foo_type {
+  a: i32,
+  b: array<u32>,
+}
+@group(0) @binding(0) var<storage, read_write> foo_sb: foo_type;
+fn sb_func() { _ = foo_sb.a; }
+@fragment fn ep_func() { sb_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2777,22 +2395,15 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, StorageBuffer_ContainingPadding) {
-    auto foo_struct_type = MakeStorageBufferTypes("foo_type", Vector{
-                                                                  ty.vec3<f32>(),
-                                                              });
-    AddStorageBuffer("foo_sb", foo_struct_type(), core::Access::kReadWrite, 0, 0);
-
-    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
-                                            Vector{
-                                                MemberInfo{0, ty.vec3<f32>()},
-                                            });
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("sb_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct foo_type {
+  a: vec3f,
+}
+@group(0) @binding(0) var<storage, read_write> foo_sb: foo_type;
+fn sb_func() { _ = foo_sb.a; }
+@fragment fn ep_func() { sb_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2806,15 +2417,12 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, StorageBuffer_NonStructVec3) {
-    AddStorageBuffer("foo_ub", ty.vec3<f32>(), core::Access::kReadWrite, 0, 0);
-    MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.vec3<f32>(), tint::Empty);
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("ub_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@group(0) @binding(0) var<storage, read_write> foo_ub: vec3f;
+fn ub_func() { _ = foo_ub; }
+@fragment fn ep_func() { ub_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2828,22 +2436,15 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, StorageBuffer_ReadOnlySimple) {
-    auto foo_struct_type = MakeStorageBufferTypes("foo_type", Vector{
-                                                                  ty.i32(),
-                                                              });
-    AddStorageBuffer("foo_sb", foo_struct_type(), core::Access::kRead, 0, 0);
-
-    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
-                                            Vector{
-                                                MemberInfo{0, ty.i32()},
-                                            });
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("sb_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct foo_type {
+  a: i32,
+}
+@group(0) @binding(0) var<storage, read> foo_sb: foo_type;
+fn sb_func() { _ = foo_sb.a; }
+@fragment fn ep_func() { sb_func(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2857,41 +2458,25 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, StorageBuffer_MultipleROAndRW) {
-    auto sb_struct_type = MakeStorageBufferTypes("sb_type", Vector{
-                                                                ty.i32(),
-                                                                ty.u32(),
-                                                                ty.f32(),
-                                                            });
-    AddStorageBuffer("sb_foo", sb_struct_type(), core::Access::kRead, 0, 0);
-    AddStorageBuffer("sb_bar", sb_struct_type(), core::Access::kReadWrite, 0, 1);
-    AddStorageBuffer("sb_baz", sb_struct_type(), core::Access::kRead, 2, 0);
-
-    auto AddReferenceFunc = [this](const std::string& func_name, const std::string& var_name) {
-        MakeStructVariableReferenceBodyFunction(func_name, var_name,
-                                                Vector{
-                                                    MemberInfo{0, ty.i32()},
-                                                    MemberInfo{1, ty.u32()},
-                                                    MemberInfo{2, ty.f32()},
-                                                });
-    };
-    AddReferenceFunc("sb_foo_func", "sb_foo");
-    AddReferenceFunc("sb_bar_func", "sb_bar");
-    AddReferenceFunc("sb_baz_func", "sb_baz");
-
-    auto FuncCall = [&](const std::string& callee) { return CallStmt(Call(callee)); };
-
-    Func("ep_func", tint::Empty, ty.void_(),
-         Vector{
-             FuncCall("sb_foo_func"),
-             FuncCall("sb_bar_func"),
-             FuncCall("sb_baz_func"),
-             Return(),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+struct sb_type {
+  a: i32,
+  b: u32,
+  c: f32,
+}
+@group(0) @binding(0) var<storage, read> sb_foo: sb_type;
+@group(0) @binding(1) var<storage, read_write> sb_bar: sb_type;
+@group(2) @binding(0) var<storage, read> sb_baz: sb_type;
+fn sb_foo_func() { _ = sb_foo.a; _ = sb_foo.b; _ = sb_foo.c; }
+fn sb_bar_func() { _ = sb_bar.a; _ = sb_bar.b; _ = sb_bar.c; }
+fn sb_baz_func() { _ = sb_baz.a; _ = sb_baz.b; _ = sb_baz.c; }
+@fragment fn ep_func() {
+  sb_foo_func();
+  sb_bar_func();
+  sb_baz_func();
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2917,17 +2502,15 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, Sampler_Simple) {
-    auto sampled_texture_type = ty.sampled_texture(core::type::TextureDimension::k1d, ty.f32());
-    AddSampler("foo_sampler", 0, 0);
-    AddResource("foo_texture", sampled_texture_type, 0, 1);
-    AddGlobalVariable("foo_coords", ty.f32());
-
-    MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords", ty.f32(),
-                                     Vector{
-                                         Stage(ast::PipelineStage::kFragment),
-                                     });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@group(0) @binding(0) var foo_sampler: sampler;
+@group(0) @binding(1) var foo_texture: texture_1d<f32>;
+var<private> foo_coords: f32;
+@fragment fn ep() {
+  _ = textureSample(foo_texture, foo_sampler, foo_coords);
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2940,20 +2523,15 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, Sampler_InFunction) {
-    auto sampled_texture_type = ty.sampled_texture(core::type::TextureDimension::k1d, ty.f32());
-    AddSampler("foo_sampler", 0, 0);
-    AddResource("foo_texture", sampled_texture_type, 0, 1);
-    AddGlobalVariable("foo_coords", ty.f32());
-
-    MakeSamplerReferenceBodyFunction("foo_func", "foo_texture", "foo_sampler", "foo_coords",
-                                     ty.f32(), tint::Empty);
-
-    MakeCallerBodyFunction("ep_func", Vector{std::string("foo_func")},
-                           Vector{
-                               Stage(ast::PipelineStage::kFragment),
-                           });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@group(0) @binding(0) var foo_sampler: sampler;
+@group(0) @binding(1) var foo_texture: texture_1d<f32>;
+var<private> foo_coords: f32;
+@fragment fn ep_func() {
+  _ = textureSample(foo_texture, foo_sampler, foo_coords);
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep_func");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2965,19 +2543,16 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, Sampler_Comparison) {
-    auto depth_texture_type = ty.depth_texture(core::type::TextureDimension::k2d);
-    AddComparisonSampler("foo_sampler", 0, 0);
-    AddResource("foo_texture", depth_texture_type, 0, 1);
-    AddGlobalVariable("foo_coords", ty.vec2<f32>());
-    AddGlobalVariable("foo_depth", ty.f32());
-
-    MakeComparisonSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
-                                               "foo_depth", ty.f32(),
-                                               Vector{
-                                                   Stage(ast::PipelineStage::kFragment),
-                                               });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@group(0) @binding(0) var foo_sampler: sampler_comparison;
+@group(0) @binding(1) var foo_texture: texture_depth_2d;
+var<private> foo_coords: vec2f;
+var<private> foo_depth: f32;
+@fragment fn ep() {
+  _ = textureSampleCompare(foo_texture, foo_sampler, foo_coords, foo_depth);
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -2988,21 +2563,45 @@
     EXPECT_EQ(0u, result[1].binding);
 }
 
+std::string CoordsType(core::type::TextureDimension dim, std::string_view name) {
+    switch (dim) {
+        case core::type::TextureDimension::k1d:
+            return std::string(name);
+        case core::type::TextureDimension::k2d:
+        case core::type::TextureDimension::k2dArray:
+            return "vec2<" + std::string(name) + ">";
+        case core::type::TextureDimension::k3d:
+        case core::type::TextureDimension::kCube:
+        case core::type::TextureDimension::kCubeArray:
+            return "vec3<" + std::string(name) + ">";
+        default:
+            break;
+    }
+    TINT_UNREACHABLE();
+}
+
+struct SampledTextureTestParams {
+    core::type::TextureDimension type_dim;
+    inspector::ResourceBinding::TextureDimension inspector_dim;
+    inspector::ResourceBinding::SampledKind sampled_kind;
+};
+using InspectorGetResourceBindingsTest_WithSampledTextureParams =
+    InspectorTestWithParam<SampledTextureTestParams>;
 TEST_P(InspectorGetResourceBindingsTest_WithSampledTextureParams, TextureSample) {
-    ast::Type sampled_texture_type =
-        ty.sampled_texture(GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
-    AddResource("foo_texture", sampled_texture_type, 0, 0);
-    AddSampler("foo_sampler", 0, 1);
-    ast::Type coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
-    AddGlobalVariable("foo_coords", coord_type);
+    auto& params = GetParam();
 
-    MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
-                                     GetBaseType(GetParam().sampled_kind),
-                                     Vector{
-                                         Stage(ast::PipelineStage::kFragment),
-                                     });
-
-    Inspector& inspector = Build();
+    auto src = R"(
+@group(0) @binding(0) var foo_texture: texture_)" +
+               std::string(ToString(params.type_dim)) +
+               R"(<f32>;
+@group(0) @binding(1) var foo_sampler: sampler;
+var<private> foo_coords: )" +
+               CoordsType(params.type_dim, "f32") + R"(;
+@fragment fn ep() {
+  _ = textureSample(foo_texture, foo_sampler, foo_coords);
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -3011,8 +2610,8 @@
     EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture, result[0].resource_type);
     EXPECT_EQ(0u, result[0].bind_group);
     EXPECT_EQ(0u, result[0].binding);
-    EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
-    EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
+    EXPECT_EQ(params.inspector_dim, result[0].dim);
+    EXPECT_EQ(params.sampled_kind, result[0].sampled_kind);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -3031,22 +2630,24 @@
                                              inspector::ResourceBinding::TextureDimension::kCube,
                                              inspector::ResourceBinding::SampledKind::kFloat}));
 
+using ArraySampledTextureTestParams = SampledTextureTestParams;
+using InspectorGetResourceBindingsTest_WithArraySampledTextureParams =
+    InspectorTestWithParam<ArraySampledTextureTestParams>;
 TEST_P(InspectorGetResourceBindingsTest_WithArraySampledTextureParams, TextureSample) {
-    ast::Type sampled_texture_type =
-        ty.sampled_texture(GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
-    AddResource("foo_texture", sampled_texture_type, 0, 0);
-    AddSampler("foo_sampler", 0, 1);
-    ast::Type coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
-    AddGlobalVariable("foo_coords", coord_type);
-    AddGlobalVariable("foo_array_index", ty.i32());
-
-    MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
-                                     "foo_array_index", GetBaseType(GetParam().sampled_kind),
-                                     Vector{
-                                         Stage(ast::PipelineStage::kFragment),
-                                     });
-
-    Inspector& inspector = Build();
+    auto& params = GetParam();
+    auto src = R"(
+@group(0) @binding(0) var foo_texture: texture_)" +
+               std::string(ToString(params.type_dim)) +
+               R"(<f32>;
+@group(0) @binding(1) var foo_sampler: sampler;
+var<private> foo_coords: )" +
+               CoordsType(params.type_dim, "f32") + R"(;
+var<private> foo_array_index: i32;
+@fragment fn ep() {
+  _ = textureSample(foo_texture, foo_sampler, foo_coords, foo_array_index);
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -3059,6 +2660,9 @@
     EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
 }
 
+using MultisampledTextureTestParams = SampledTextureTestParams;
+using InspectorGetResourceBindingsTest_WithMultisampledTextureParams =
+    InspectorTestWithParam<MultisampledTextureTestParams>;
 INSTANTIATE_TEST_SUITE_P(
     InspectorGetResourceBindingsTest,
     InspectorGetResourceBindingsTest_WithArraySampledTextureParams,
@@ -3070,23 +2674,32 @@
                                       inspector::ResourceBinding::TextureDimension::kCubeArray,
                                       inspector::ResourceBinding::SampledKind::kFloat}));
 
+std::string BaseType(ResourceBinding::SampledKind sampled_kind) {
+    switch (sampled_kind) {
+        case ResourceBinding::SampledKind::kFloat:
+            return "f32";
+        case ResourceBinding::SampledKind::kSInt:
+            return "i32";
+        case ResourceBinding::SampledKind::kUInt:
+            return "u32";
+        default:
+            TINT_UNREACHABLE();
+    }
+}
+
 TEST_P(InspectorGetResourceBindingsTest_WithMultisampledTextureParams, TextureLoad) {
-    ast::Type multisampled_texture_type =
-        ty.multisampled_texture(GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
-    AddResource("foo_texture", multisampled_texture_type, 0, 0);
-    ast::Type coord_type = GetCoordsType(GetParam().type_dim, ty.i32());
-    AddGlobalVariable("foo_coords", coord_type);
-    AddGlobalVariable("foo_sample_index", ty.i32());
-
-    Func("ep", tint::Empty, ty.void_(),
-         Vector{
-             Assign(Phony(), Call("textureLoad", "foo_texture", "foo_coords", "foo_sample_index")),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto& params = GetParam();
+    auto src = R"(
+@group(0) @binding(0) var foo_texture: texture_multisampled_)" +
+               std::string(ToString(params.type_dim)) + "<" + BaseType(params.sampled_kind) + R"(>;
+var<private> foo_coords: )" +
+               CoordsType(params.type_dim, "i32") + R"(;
+var<private> foo_sample_index: i32;
+@fragment fn ep() {
+  _ = textureLoad(foo_texture, foo_coords, foo_sample_index);
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -3112,6 +2725,12 @@
                                                   inspector::ResourceBinding::TextureDimension::k2d,
                                                   inspector::ResourceBinding::SampledKind::kUInt}));
 
+using DimensionParams = std::tuple<core::type::TextureDimension, ResourceBinding::TextureDimension>;
+using TexelFormatParams =
+    std::tuple<core::TexelFormat, ResourceBinding::TexelFormat, ResourceBinding::SampledKind>;
+using StorageTextureTestParams = std::tuple<DimensionParams, TexelFormatParams, core::Access>;
+using InspectorGetResourceBindingsTest_WithStorageTextureParams =
+    InspectorTestWithParam<StorageTextureTestParams>;
 TEST_P(InspectorGetResourceBindingsTest_WithStorageTextureParams, Simple) {
     DimensionParams dim_params;
     TexelFormatParams format_params;
@@ -3143,33 +2762,13 @@
             break;
     }
 
-    ast::Type st_type = MakeStorageTextureTypes(dim, format, access);
-    AddStorageTexture("st_var", st_type, 0, 0);
-
-    ast::Type dim_type;
-    switch (dim) {
-        case core::type::TextureDimension::k1d:
-            dim_type = ty.u32();
-            break;
-        case core::type::TextureDimension::k2d:
-        case core::type::TextureDimension::k2dArray:
-            dim_type = ty.vec2<u32>();
-            break;
-        case core::type::TextureDimension::k3d:
-            dim_type = ty.vec3<u32>();
-            break;
-        default:
-            break;
-    }
-
-    ASSERT_FALSE(dim_type == nullptr);
-
-    MakeStorageTextureBodyFunction("ep", "st_var", dim_type,
-                                   Vector{
-                                       Stage(ast::PipelineStage::kFragment),
-                                   });
-
-    Inspector& inspector = Build();
+    auto src = R"(
+@group(0) @binding(0) var st_var: texture_storage_)" +
+               std::string(ToString(dim)) + "<" + std::string(ToString(format)) + ", " +
+               std::string(ToString(access)) + R"(>;
+@fragment fn ep() { _ = textureDimensions(st_var); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -3245,19 +2844,22 @@
                                         ResourceBinding::SampledKind::kFloat)),
         testing::Values(core::Access::kRead, core::Access::kWrite, core::Access::kReadWrite)));
 
+struct DepthTextureTestParams {
+    core::type::TextureDimension type_dim;
+    inspector::ResourceBinding::TextureDimension inspector_dim;
+};
+using InspectorGetResourceBindingsTest_WithDepthTextureParams =
+    InspectorTestWithParam<DepthTextureTestParams>;
 TEST_P(InspectorGetResourceBindingsTest_WithDepthTextureParams, TextureDimensions) {
-    auto depth_texture_type = ty.depth_texture(GetParam().type_dim);
-    AddResource("dt", depth_texture_type, 0, 0);
-
-    Func("ep", tint::Empty, ty.void_(),
-         Vector{
-             Assign(Phony(), Call("textureDimensions", "dt")),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto& params = GetParam();
+    auto src = R"(
+@group(0) @binding(0) var dt: texture_depth_)" +
+               std::string(ToString(params.type_dim)) + R"(;
+@fragment fn ep() {
+  _ = textureDimensions(dt);
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -3266,7 +2868,7 @@
     ASSERT_EQ(1u, result.size());
     EXPECT_EQ(0u, result[0].bind_group);
     EXPECT_EQ(0u, result[0].binding);
-    EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
+    EXPECT_EQ(params.inspector_dim, result[0].dim);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -3283,18 +2885,13 @@
                         inspector::ResourceBinding::TextureDimension::kCubeArray}));
 
 TEST_F(InspectorGetResourceBindingsTest, DepthMultisampledTexture_TextureDimensions) {
-    auto depth_ms_texture_type = ty.depth_multisampled_texture(core::type::TextureDimension::k2d);
-    AddResource("tex", depth_ms_texture_type, 0, 0);
-
-    Func("ep", tint::Empty, ty.void_(),
-         Vector{
-             Assign(Phony(), Call("textureDimensions", "tex")),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@group(0) @binding(0) var tex: texture_depth_multisampled_2d;
+@fragment fn ep() {
+  _ = textureDimensions(tex);
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -3307,18 +2904,11 @@
 }
 
 TEST_F(InspectorGetResourceBindingsTest, ExternalTexture) {
-    auto external_texture_type = ty.external_texture();
-    AddResource("et", external_texture_type, 0, 0);
-
-    Func("ep", tint::Empty, ty.void_(),
-         Vector{
-             Assign(Phony(), Call("textureDimensions", "et")),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+    auto* src = R"(
+@group(0) @binding(0) var et: texture_external;
+@fragment fn ep() { _ = textureDimensions(et); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetResourceBindings("ep");
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -3329,7 +2919,7 @@
     EXPECT_EQ(0u, result[0].binding);
 }
 
-class InspectorGetSamplerTextureUsesTest : public InspectorBuilder, public testing::Test {
+class InspectorGetSamplerTextureUsesTest : public TestHelper, public testing::Test {
   public:
     using ResultExpectation = std::initializer_list<SamplerTexturePair>;
 
@@ -4430,24 +4020,21 @@
 }
 
 TEST_F(InspectorGetBlendSrcTest, Basic) {
-    Enable(wgsl::Extension::kDualSourceBlending);
+    auto* src = R"(
+enable dual_source_blending;
 
-    Structure("out_struct",
-              Vector{
-                  Member("output_color", ty.vec4<f32>(), Vector{Location(0_u), BlendSrc(0_u)}),
-                  Member("output_blend", ty.vec4<f32>(), Vector{Location(0_u), BlendSrc(1_u)}),
-              });
+struct out_struct {
+  @location(0u) @blend_src(0u) output_color: vec4f,
+  @location(0u) @blend_src(1u) output_blend: vec4f,
+}
 
-    Func("ep_func", tint::Empty, ty("out_struct"),
-         Vector{
-             Decl(Var("out_var", ty("out_struct"))),
-             Return("out_var"),
-         },
-         Vector{
-             Stage(ast::PipelineStage::kFragment),
-         });
-
-    Inspector& inspector = Build();
+@fragment
+fn ep_func() -> out_struct {
+  var out_var: out_struct;
+  return out_var;
+}
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
 
@@ -4458,18 +4045,13 @@
 }
 
 TEST_F(InspectorSubgroupMatrixTest, DirectUse) {
-    Enable(wgsl::Extension::kChromiumExperimentalSubgroupMatrix);
+    auto* src = R"(
+enable chromium_experimental_subgroup_matrix;
 
-    GlobalVar("sm", ty.subgroup_matrix(core::SubgroupMatrixKind::kResult, ty.f32(), 8, 8),
-              core::AddressSpace::kPrivate);
-    MakePlainGlobalReferenceBodyFunction(
-        "foo", "sm", ty.subgroup_matrix(core::SubgroupMatrixKind::kResult, ty.f32(), 8, 8),
-        Vector{
-            Stage(ast::PipelineStage::kCompute),
-            WorkgroupSize(1_a),
-        });
-
-    Inspector& inspector = Build();
+var<private> sm: subgroup_matrix_result<f32, 8, 8>;
+@compute @workgroup_size(1) fn foo() { _ = sm; }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();
@@ -4479,19 +4061,14 @@
 }
 
 TEST_F(InspectorSubgroupMatrixTest, IndirectUse) {
-    Enable(wgsl::Extension::kChromiumExperimentalSubgroupMatrix);
+    auto* src = R"(
+enable chromium_experimental_subgroup_matrix;
 
-    GlobalVar("sm", ty.subgroup_matrix(core::SubgroupMatrixKind::kResult, ty.f32(), 8, 8),
-              core::AddressSpace::kPrivate);
-    MakePlainGlobalReferenceBodyFunction(
-        "foo", "sm", ty.subgroup_matrix(core::SubgroupMatrixKind::kResult, ty.f32(), 8, 8), Empty);
-    MakeCallerBodyFunction("main", Vector{std::string("foo")},
-                           Vector{
-                               Stage(ast::PipelineStage::kCompute),
-                               WorkgroupSize(1_a),
-                           });
-
-    Inspector& inspector = Build();
+var<private> sm: subgroup_matrix_result<f32, 8, 8>;
+fn foo() { _ = sm; }
+@compute @workgroup_size(1) fn main() { foo(); }
+)";
+    Inspector& inspector = Initialize(src);
 
     auto result = inspector.GetEntryPoints();
     ASSERT_FALSE(inspector.has_error()) << inspector.error();