[tint][fuzzer] Fix bad mutation

An ast::CallStatement's expression must only be an ast::CallExpression.
Prevent the mutator fuzzer from attempting to mutate the CallExpression with something else.

Bug: chromium:1383368
Change-Id: I55ae2b9dfb16214ad708baa61005e00a80ce9a63
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/140180
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.cc
index 25ac065..6f6efc2 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.cc
@@ -18,6 +18,8 @@
 #include <vector>
 
 #include "src/tint/program_builder.h"
+#include "src/tint/sem/call.h"
+#include "src/tint/sem/statement.h"
 #include "src/tint/type/abstract_float.h"
 #include "src/tint/type/abstract_int.h"
 
@@ -94,6 +96,16 @@
 
 std::vector<ast::UnaryOp> MutationWrapUnaryOperator::GetValidUnaryWrapper(
     const sem::ValueExpression& expr) {
+    if (auto* call_expr = expr.As<sem::Call>()) {
+        if (auto* stmt = call_expr->Stmt()) {
+            if (auto* call_stmt = stmt->Declaration()->As<ast::CallStatement>()) {
+                if (call_stmt->expr == expr.Declaration()) {
+                    return {};  // A call statement must only wrap a call expression.
+                }
+            }
+        }
+    }
+
     const auto* expr_type = expr.Type();
     if (expr_type->is_bool_scalar_or_vector()) {
         return {ast::UnaryOp::kNot};
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator_test.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator_test.cc
index c73c1b3..91c9453 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator_test.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator_test.cc
@@ -519,5 +519,34 @@
         node_id_map, &program, &node_id_map, nullptr));
 }
 
+TEST(WrapUnaryOperatorTest, NotApplicable_CallStmt) {
+    std::string content = R"(
+    fn main() {
+      f();
+    }
+    fn f() -> bool {
+      return false;
+    }
+  )";
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    NodeIdMap node_id_map(program);
+
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
+
+    const auto* call_stmt = main_fn_statements[0]->As<ast::CallStatement>();
+    ASSERT_NE(call_stmt, nullptr);
+
+    const auto expr_id = node_id_map.GetId(call_stmt->expr);
+    ASSERT_NE(expr_id, 0);
+
+    // The id provided for the expression is not a valid expression type.
+    ASSERT_FALSE(MaybeApplyMutation(
+        program, MutationWrapUnaryOperator(expr_id, node_id_map.TakeFreshId(), ast::UnaryOp::kNot),
+        node_id_map, &program, &node_id_map, nullptr));
+}
+
 }  // namespace
 }  // namespace tint::fuzzers::ast_fuzzer