Add test, shuffle code before changes.

Add a disabled regression test for the issue, the code is moved to group
the three methods together. The two moved functions are only called from
`GetSamplerTextureUses` so this just moves them together to make working
with them easier.

Bug: 380433758
Change-Id: I0b61a8debafd28d63bcd316d62c01b5ebccf60c5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/223514
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/wgsl/inspector/inspector.cc b/src/tint/lang/wgsl/inspector/inspector.cc
index 6382d60..bae62ee 100644
--- a/src/tint/lang/wgsl/inspector/inspector.cc
+++ b/src/tint/lang/wgsl/inspector/inspector.cc
@@ -603,6 +603,129 @@
     return it->second;
 }
 
+void Inspector::GenerateSamplerTargets() {
+    // Do not re-generate, since |program_| should not change during the lifetime
+    // of the inspector.
+    if (sampler_targets_ != nullptr) {
+        return;
+    }
+
+    sampler_targets_ =
+        std::make_unique<std::unordered_map<std::string, UniqueVector<SamplerTexturePair, 4>>>();
+
+    auto& sem = program_.Sem();
+
+    for (auto* node : program_.ASTNodes().Objects()) {
+        auto* c = node->As<ast::CallExpression>();
+        if (!c) {
+            continue;
+        }
+
+        auto* call = sem.Get(c)->UnwrapMaterialize()->As<sem::Call>();
+        if (!call) {
+            continue;
+        }
+
+        auto* i = call->Target()->As<sem::BuiltinFn>();
+        if (!i) {
+            continue;
+        }
+
+        const auto& signature = i->Signature();
+        int sampler_index = signature.IndexOf(core::ParameterUsage::kSampler);
+        if (sampler_index == -1) {
+            continue;
+        }
+
+        int texture_index = signature.IndexOf(core::ParameterUsage::kTexture);
+        if (texture_index == -1) {
+            continue;
+        }
+
+        auto* call_func = call->Stmt()->Function();
+        Vector<const sem::Function*, 4> entry_points;
+        if (call_func->Declaration()->IsEntryPoint()) {
+            entry_points = {call_func};
+        } else {
+            entry_points = call_func->AncestorEntryPoints();
+        }
+
+        if (entry_points.IsEmpty()) {
+            continue;
+        }
+
+        auto* t = c->args[static_cast<size_t>(texture_index)];
+        auto* s = c->args[static_cast<size_t>(sampler_index)];
+
+        GetOriginatingResources(
+            std::array<const ast::Expression*, 2>{t, s},
+            [&](std::array<const sem::GlobalVariable*, 2> globals) {
+                auto texture_binding_point = *globals[0]->Attributes().binding_point;
+                auto sampler_binding_point = *globals[1]->Attributes().binding_point;
+
+                for (auto* entry_point : entry_points) {
+                    const auto& ep_name = entry_point->Declaration()->name->symbol.Name();
+                    (*sampler_targets_)[ep_name].Add(
+                        {sampler_binding_point, texture_binding_point});
+                }
+            });
+    }
+}
+
+template <size_t N, typename F>
+void Inspector::GetOriginatingResources(std::array<const ast::Expression*, N> exprs, F&& callback) {
+    if (DAWN_UNLIKELY(!program_.IsValid())) {
+        TINT_ICE() << "attempting to get originating resources in invalid program";
+        return;
+    }
+
+    auto& sem = program_.Sem();
+
+    std::array<const sem::GlobalVariable*, N> globals{};
+    std::array<const sem::Parameter*, N> parameters{};
+    UniqueVector<const ast::CallExpression*, 8> callsites;
+
+    for (size_t i = 0; i < N; i++) {
+        const sem::Variable* root_ident = sem.GetVal(exprs[i])->RootIdentifier();
+        if (auto* global = root_ident->As<sem::GlobalVariable>()) {
+            globals[i] = global;
+        } else if (auto* param = root_ident->As<sem::Parameter>()) {
+            auto* func = tint::As<sem::Function>(param->Owner());
+            if (func->CallSites().IsEmpty()) {
+                // One or more of the expressions is a parameter, but this function
+                // is not called. Ignore.
+                return;
+            }
+            for (auto* call : func->CallSites()) {
+                callsites.Add(call->Declaration());
+            }
+            parameters[i] = param;
+        } else {
+            TINT_ICE() << "cannot resolve originating resource with expression type "
+                       << exprs[i]->TypeInfo().name;
+            return;
+        }
+    }
+
+    if (callsites.Length()) {
+        for (auto* call_expr : callsites) {
+            // Make a copy of the expressions for this callsite
+            std::array<const ast::Expression*, N> call_exprs = exprs;
+            // Patch all the parameter expressions with their argument
+            for (size_t i = 0; i < N; i++) {
+                if (auto* param = parameters[i]) {
+                    call_exprs[i] = call_expr->args[param->Index()];
+                }
+            }
+            // Now call GetOriginatingResources() with from the callsite
+            GetOriginatingResources(call_exprs, callback);
+        }
+    } else {
+        // All the expressions resolved to globals
+        callback(globals);
+    }
+}
+
 std::vector<SamplerTexturePair> Inspector::GetSamplerTextureUses(const std::string& entry_point,
                                                                  const BindingPoint& placeholder) {
     auto* func = FindEntryPointByName(entry_point);
@@ -879,75 +1002,6 @@
     return result;
 }
 
-void Inspector::GenerateSamplerTargets() {
-    // Do not re-generate, since |program_| should not change during the lifetime
-    // of the inspector.
-    if (sampler_targets_ != nullptr) {
-        return;
-    }
-
-    sampler_targets_ =
-        std::make_unique<std::unordered_map<std::string, UniqueVector<SamplerTexturePair, 4>>>();
-
-    auto& sem = program_.Sem();
-
-    for (auto* node : program_.ASTNodes().Objects()) {
-        auto* c = node->As<ast::CallExpression>();
-        if (!c) {
-            continue;
-        }
-
-        auto* call = sem.Get(c)->UnwrapMaterialize()->As<sem::Call>();
-        if (!call) {
-            continue;
-        }
-
-        auto* i = call->Target()->As<sem::BuiltinFn>();
-        if (!i) {
-            continue;
-        }
-
-        const auto& signature = i->Signature();
-        int sampler_index = signature.IndexOf(core::ParameterUsage::kSampler);
-        if (sampler_index == -1) {
-            continue;
-        }
-
-        int texture_index = signature.IndexOf(core::ParameterUsage::kTexture);
-        if (texture_index == -1) {
-            continue;
-        }
-
-        auto* call_func = call->Stmt()->Function();
-        Vector<const sem::Function*, 4> entry_points;
-        if (call_func->Declaration()->IsEntryPoint()) {
-            entry_points = {call_func};
-        } else {
-            entry_points = call_func->AncestorEntryPoints();
-        }
-
-        if (entry_points.IsEmpty()) {
-            continue;
-        }
-
-        auto* t = c->args[static_cast<size_t>(texture_index)];
-        auto* s = c->args[static_cast<size_t>(sampler_index)];
-
-        GetOriginatingResources(
-            std::array<const ast::Expression*, 2>{t, s},
-            [&](std::array<const sem::GlobalVariable*, 2> globals) {
-                auto texture_binding_point = *globals[0]->Attributes().binding_point;
-                auto sampler_binding_point = *globals[1]->Attributes().binding_point;
-
-                for (auto* entry_point : entry_points) {
-                    const auto& ep_name = entry_point->Declaration()->name->symbol.Name();
-                    (*sampler_targets_)[ep_name].Add(
-                        {sampler_binding_point, texture_binding_point});
-                }
-            });
-    }
-}
-
 std::tuple<InterpolationType, InterpolationSampling> Inspector::CalculateInterpolationData(
     VectorRef<const ast::Attribute*> attributes) const {
     auto* interpolation_attribute = ast::GetAttribute<ast::InterpolateAttribute>(attributes);
@@ -1067,60 +1121,6 @@
     return {};
 }
 
-template <size_t N, typename F>
-void Inspector::GetOriginatingResources(std::array<const ast::Expression*, N> exprs, F&& callback) {
-    if (DAWN_UNLIKELY(!program_.IsValid())) {
-        TINT_ICE() << "attempting to get originating resources in invalid program";
-        return;
-    }
-
-    auto& sem = program_.Sem();
-
-    std::array<const sem::GlobalVariable*, N> globals{};
-    std::array<const sem::Parameter*, N> parameters{};
-    UniqueVector<const ast::CallExpression*, 8> callsites;
-
-    for (size_t i = 0; i < N; i++) {
-        const sem::Variable* root_ident = sem.GetVal(exprs[i])->RootIdentifier();
-        if (auto* global = root_ident->As<sem::GlobalVariable>()) {
-            globals[i] = global;
-        } else if (auto* param = root_ident->As<sem::Parameter>()) {
-            auto* func = tint::As<sem::Function>(param->Owner());
-            if (func->CallSites().IsEmpty()) {
-                // One or more of the expressions is a parameter, but this function
-                // is not called. Ignore.
-                return;
-            }
-            for (auto* call : func->CallSites()) {
-                callsites.Add(call->Declaration());
-            }
-            parameters[i] = param;
-        } else {
-            TINT_ICE() << "cannot resolve originating resource with expression type "
-                       << exprs[i]->TypeInfo().name;
-            return;
-        }
-    }
-
-    if (callsites.Length()) {
-        for (auto* call_expr : callsites) {
-            // Make a copy of the expressions for this callsite
-            std::array<const ast::Expression*, N> call_exprs = exprs;
-            // Patch all the parameter expressions with their argument
-            for (size_t i = 0; i < N; i++) {
-                if (auto* param = parameters[i]) {
-                    call_exprs[i] = call_expr->args[param->Index()];
-                }
-            }
-            // Now call GetOriginatingResources() with from the callsite
-            GetOriginatingResources(call_exprs, callback);
-        }
-    } else {
-        // All the expressions resolved to globals
-        callback(globals);
-    }
-}
-
 std::vector<Inspector::LevelSampleInfo> Inspector::GetTextureQueries(const std::string& ep_name) {
     const auto* ep = FindEntryPointByName(ep_name);
     if (!ep) {
diff --git a/src/tint/lang/wgsl/inspector/inspector_test.cc b/src/tint/lang/wgsl/inspector/inspector_test.cc
index 6a93800..8cea0aa 100644
--- a/src/tint/lang/wgsl/inspector/inspector_test.cc
+++ b/src/tint/lang/wgsl/inspector/inspector_test.cc
@@ -3508,6 +3508,56 @@
     ASSERT_EQ(0u, result.Length());
 }
 
+// Regression test for crbug.com/dawn/380433758.
+TEST_F(InspectorGetSamplerTextureUsesTest, DISABLED_DiamondSampler) {
+    std::string shader = R"(
+fn sample(t: texture_2d<f32>, s: sampler) -> vec4f {
+  return textureSampleLevel(t, s, vec2f(0), 0);
+}
+
+fn useCombos0() -> vec4f {
+  return sample(tex0_0, smp0_0);
+}
+
+fn useCombos1() -> vec4f {
+  return sample(tex1_15, smp0_0);
+}
+
+@group(0) @binding(0) var tex0_0: texture_2d<f32>;
+@group(0) @binding(1) var tex1_15: texture_2d<f32>;
+@group(0) @binding(2) var smp0_0: sampler;
+
+@vertex fn vs() -> @builtin(position) vec4f {
+  return useCombos0();
+}
+
+@fragment fn fs() -> @location(0) vec4f {
+  return vec4f(useCombos1());
+})";
+
+    Inspector& inspector = Initialize(shader);
+    {
+        auto result = inspector.GetSamplerTextureUses("vs");
+        ASSERT_FALSE(inspector.has_error()) << inspector.error();
+        ASSERT_EQ(1u, result.Length());
+
+        EXPECT_EQ(0u, result[0].sampler_binding_point.group);
+        EXPECT_EQ(2u, result[0].sampler_binding_point.binding);
+        EXPECT_EQ(0u, result[0].texture_binding_point.group);
+        EXPECT_EQ(0u, result[0].texture_binding_point.binding);
+    }
+    {
+        auto result = inspector.GetSamplerTextureUses("fs");
+        ASSERT_FALSE(inspector.has_error()) << inspector.error();
+        ASSERT_EQ(1u, result.Length());
+
+        EXPECT_EQ(0u, result[0].sampler_binding_point.group);
+        EXPECT_EQ(2u, result[0].sampler_binding_point.binding);
+        EXPECT_EQ(0u, result[0].texture_binding_point.group);
+        EXPECT_EQ(1u, result[0].texture_binding_point.binding);
+    }
+}
+
 TEST_F(InspectorGetSamplerTextureUsesTest, Simple) {
     std::string shader = R"(
 @group(0) @binding(1) var mySampler: sampler;