[ast] Add decorations to functions.

This CL extends the function AST object to allow function decorations to
be attached.

Change-Id: I5b16aa2e6927792368b7f88047c0229e258b5bd3
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/28661
Reviewed-by: Sarah Mashayekhi <sarahmashay@google.com>
Commit-Queue: Sarah Mashayekhi <sarahmashay@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 67cd7b8..9833709 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -265,6 +265,8 @@
     "src/ast/float_literal.h",
     "src/ast/function.cc",
     "src/ast/function.h",
+    "src/ast/function_decoration.cc",
+    "src/ast/function_decoration.h",
     "src/ast/identifier_expression.cc",
     "src/ast/identifier_expression.h",
     "src/ast/if_statement.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 33cd006..f821429 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -86,6 +86,8 @@
   ast/float_literal.h
   ast/function.cc
   ast/function.h
+  ast/function_decoration.cc
+  ast/function_decoration.h
   ast/identifier_expression.cc
   ast/identifier_expression.h
   ast/if_statement.cc
diff --git a/src/ast/function.cc b/src/ast/function.cc
index 23a1583..0e52bf9 100644
--- a/src/ast/function.cc
+++ b/src/ast/function.cc
@@ -191,6 +191,11 @@
   out << "Function " << name_ << " -> " << return_type_->type_name()
       << std::endl;
 
+  for (const auto& deco : decorations()) {
+    make_indent(out, indent);
+    deco->to_str(out);
+  }
+
   make_indent(out, indent);
   out << "(";
 
diff --git a/src/ast/function.h b/src/ast/function.h
index 31897cf..b292464 100644
--- a/src/ast/function.h
+++ b/src/ast/function.h
@@ -25,6 +25,7 @@
 #include "src/ast/block_statement.h"
 #include "src/ast/builtin_decoration.h"
 #include "src/ast/expression.h"
+#include "src/ast/function_decoration.h"
 #include "src/ast/location_decoration.h"
 #include "src/ast/node.h"
 #include "src/ast/set_decoration.h"
@@ -81,6 +82,14 @@
   /// @returns the function params
   const VariableList& params() const { return params_; }
 
+  /// Adds a decoration to the function
+  /// @param deco the decoration to set
+  void add_decoration(std::unique_ptr<FunctionDecoration> deco) {
+    decorations_.push_back(std::move(deco));
+  }
+  /// @returns the decorations attached to this function
+  const FunctionDecorationList& decorations() const { return decorations_; }
+
   /// Adds the given variable to the list of referenced module variables if it
   /// is not already included.
   /// @param var the module variable to add
@@ -157,6 +166,7 @@
   std::unique_ptr<BlockStatement> body_;
   std::vector<Variable*> referenced_module_vars_;
   std::vector<std::string> ancestor_entry_points_;
+  FunctionDecorationList decorations_;
 };
 
 /// A list of unique functions
diff --git a/src/ast/function_decoration.cc b/src/ast/function_decoration.cc
new file mode 100644
index 0000000..a447297
--- /dev/null
+++ b/src/ast/function_decoration.cc
@@ -0,0 +1,25 @@
+// Copyright 2020 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/ast/function_decoration.h"
+
+namespace tint {
+namespace ast {
+
+FunctionDecoration::FunctionDecoration() = default;
+
+FunctionDecoration::~FunctionDecoration() = default;
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/function_decoration.h b/src/ast/function_decoration.h
new file mode 100644
index 0000000..4b75f30
--- /dev/null
+++ b/src/ast/function_decoration.h
@@ -0,0 +1,44 @@
+// Copyright 2020 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_AST_FUNCTION_DECORATION_H_
+#define SRC_AST_FUNCTION_DECORATION_H_
+
+#include <memory>
+#include <ostream>
+#include <vector>
+
+namespace tint {
+namespace ast {
+
+/// A decoration attached to a function
+class FunctionDecoration {
+ public:
+  virtual ~FunctionDecoration();
+
+  /// Outputs the function decoration to the given stream
+  /// @param out the stream to output too
+  virtual void to_str(std::ostream& out) const = 0;
+
+ protected:
+  FunctionDecoration();
+};
+
+/// A list of unique function decorations
+using FunctionDecorationList = std::vector<std::unique_ptr<FunctionDecoration>>;
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_FUNCTION_DECORATION_H_
diff --git a/src/ast/function_test.cc b/src/ast/function_test.cc
index f374363..a75a619 100644
--- a/src/ast/function_test.cc
+++ b/src/ast/function_test.cc
@@ -24,6 +24,7 @@
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/void_type.h"
 #include "src/ast/variable.h"
+// #include "src/ast/workgroup_decoration.h"
 
 namespace tint {
 namespace ast {
@@ -297,6 +298,28 @@
 )");
 }
 
+// TEST_F(FunctionTest, ToStr_WithDecoration) {
+//   type::VoidType void_type;
+//   type::I32Type i32;
+
+//   auto block = std::make_unique<ast::BlockStatement>();
+//   block->append(std::make_unique<DiscardStatement>());
+
+//   Function f("func", {}, &void_type);
+//   f.set_body(std::move(block));
+//   f.add_decoration(std::make_unique<WorkgroupDecoration>(2, 4, 6));
+
+//   std::ostringstream out;
+//   f.to_str(out, 2);
+//   EXPECT_EQ(out.str(), R"(  Function func -> __void
+//   workgroup_size 2 4 6
+//   ()
+//   {
+//     Discard{}
+//   }
+// )");
+// }
+
 TEST_F(FunctionTest, ToStr_WithParams) {
   type::VoidType void_type;
   type::I32Type i32;