tint/ast: Add DiagnosticAttribute AST node

Bug: tint:1809
Change-Id: I297d050e001f5177a6697d8332713a1f41899b87
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/117562
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 451a38f..ab97247 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -232,6 +232,8 @@
     "ast/depth_multisampled_texture.h",
     "ast/depth_texture.cc",
     "ast/depth_texture.h",
+    "ast/diagnostic_attribute.cc",
+    "ast/diagnostic_attribute.h",
     "ast/diagnostic_control.cc",
     "ast/diagnostic_control.h",
     "ast/disable_validation_attribute.cc",
@@ -1183,6 +1185,7 @@
       "ast/compound_assignment_statement_test.cc",
       "ast/const_assert_test.cc",
       "ast/continue_statement_test.cc",
+      "ast/diagnostic_attribute_test.cc",
       "ast/diagnostic_control_test.cc",
       "ast/discard_statement_test.cc",
       "ast/enable_test.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 9fac34d..b9837c9 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -127,6 +127,8 @@
   ast/depth_multisampled_texture.h
   ast/depth_texture.cc
   ast/depth_texture.h
+  ast/diagnostic_attribute.cc
+  ast/diagnostic_attribute.h
   ast/diagnostic_control.cc
   ast/diagnostic_control.h
   ast/disable_validation_attribute.cc
@@ -835,6 +837,7 @@
     ast/continue_statement_test.cc
     ast/depth_multisampled_texture_test.cc
     ast/depth_texture_test.cc
+    ast/diagnostic_attribute_test.cc
     ast/diagnostic_control_test.cc
     ast/discard_statement_test.cc
     ast/enable_test.cc
diff --git a/src/tint/ast/diagnostic_attribute.cc b/src/tint/ast/diagnostic_attribute.cc
new file mode 100644
index 0000000..21f698e
--- /dev/null
+++ b/src/tint/ast/diagnostic_attribute.cc
@@ -0,0 +1,44 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/diagnostic_attribute.h"
+
+#include <string>
+
+#include "src/tint/program_builder.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::DiagnosticAttribute);
+
+namespace tint::ast {
+
+DiagnosticAttribute::DiagnosticAttribute(ProgramID pid,
+                                         NodeID nid,
+                                         const Source& src,
+                                         const ast::DiagnosticControl* dc)
+    : Base(pid, nid, src), control(dc) {}
+
+DiagnosticAttribute::~DiagnosticAttribute() = default;
+
+std::string DiagnosticAttribute::Name() const {
+    return "diagnostic";
+}
+
+const DiagnosticAttribute* DiagnosticAttribute::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto dc = ctx->Clone(control);
+    return ctx->dst->create<DiagnosticAttribute>(src, dc);
+}
+
+}  // namespace tint::ast
diff --git a/src/tint/ast/diagnostic_attribute.h b/src/tint/ast/diagnostic_attribute.h
new file mode 100644
index 0000000..7e0c514
--- /dev/null
+++ b/src/tint/ast/diagnostic_attribute.h
@@ -0,0 +1,53 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_AST_DIAGNOSTIC_ATTRIBUTE_H_
+#define SRC_TINT_AST_DIAGNOSTIC_ATTRIBUTE_H_
+
+#include <string>
+
+#include "src/tint/ast/attribute.h"
+#include "src/tint/ast/diagnostic_control.h"
+
+namespace tint::ast {
+
+/// A diagnostic attribute
+class DiagnosticAttribute final : public Castable<DiagnosticAttribute, Attribute> {
+  public:
+    /// constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param nid the unique node identifier
+    /// @param src the source of this node
+    /// @param dc the diagnostic control
+    DiagnosticAttribute(ProgramID pid,
+                        NodeID nid,
+                        const Source& src,
+                        const ast::DiagnosticControl* dc);
+    ~DiagnosticAttribute() override;
+
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
+
+    /// Clones this node and all transitive child nodes using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const DiagnosticAttribute* Clone(CloneContext* ctx) const override;
+
+    /// The diagnostic control expression.
+    const ast::DiagnosticControl* const control;
+};
+
+}  // namespace tint::ast
+
+#endif  // SRC_TINT_AST_DIAGNOSTIC_ATTRIBUTE_H_
diff --git a/src/tint/ast/diagnostic_attribute_test.cc b/src/tint/ast/diagnostic_attribute_test.cc
new file mode 100644
index 0000000..d7f0779
--- /dev/null
+++ b/src/tint/ast/diagnostic_attribute_test.cc
@@ -0,0 +1,32 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/test_helper.h"
+
+namespace tint::ast {
+namespace {
+
+using namespace tint::number_suffixes;  // NOLINT
+using DiagnosticAttributeTest = TestHelper;
+
+TEST_F(DiagnosticAttributeTest, Creation) {
+    auto* name = Expr("foo");
+    auto* d = DiagnosticAttribute(DiagnosticSeverity::kWarning, name);
+    EXPECT_EQ(d->Name(), "diagnostic");
+    EXPECT_EQ(d->control->severity, DiagnosticSeverity::kWarning);
+    EXPECT_EQ(d->control->rule_name, name);
+}
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 2d50c36..8c8f2e8 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -41,6 +41,7 @@
 #include "src/tint/ast/continue_statement.h"
 #include "src/tint/ast/depth_multisampled_texture.h"
 #include "src/tint/ast/depth_texture.h"
+#include "src/tint/ast/diagnostic_attribute.h"
 #include "src/tint/ast/diagnostic_control.h"
 #include "src/tint/ast/disable_validation_attribute.h"
 #include "src/tint/ast/discard_statement.h"
@@ -3221,6 +3222,30 @@
                                                                   validation);
     }
 
+    /// Creates an ast::DiagnosticAttribute
+    /// @param source the source information
+    /// @param severity the diagnostic severity control
+    /// @param rule_name the diagnostic rule name
+    /// @returns the diagnostic attribute pointer
+    const ast::DiagnosticAttribute* DiagnosticAttribute(
+        const Source& source,
+        ast::DiagnosticSeverity severity,
+        const ast::IdentifierExpression* rule_name) {
+        return create<ast::DiagnosticAttribute>(source,
+                                                DiagnosticControl(source, severity, rule_name));
+    }
+
+    /// Creates an ast::DiagnosticAttribute
+    /// @param severity the diagnostic severity control
+    /// @param rule_name the diagnostic rule name
+    /// @returns the diagnostic attribute pointer
+    const ast::DiagnosticAttribute* DiagnosticAttribute(
+        ast::DiagnosticSeverity severity,
+        const ast::IdentifierExpression* rule_name) {
+        return create<ast::DiagnosticAttribute>(source_,
+                                                DiagnosticControl(source_, severity, rule_name));
+    }
+
     /// Creates an ast::DiagnosticControl
     /// @param source the source information
     /// @param severity the diagnostic severity control