[Rust,front-end,v2,20/37] gccrs: Add attributes checker

Message ID 20220824115956.737931-21-philip.herron@embecosm.com
State New
Headers
Series [Rust,front-end,v2,01/37] Use DW_ATE_UTF for the Rust 'char' type |

Commit Message

herron.philip@googlemail.com Aug. 24, 2022, 11:59 a.m. UTC
  From: Arthur Cohen <arthur.cohen@embecosm.com>

The attribute checker is responsible for checking the validity of various
attributes including built-in ones. It is currently unfinished and will
receive some modifications, as well as become the host of some existing
code in the compiler which needs to be refactored. One of its
responsibilities is to make sure that arguments given to built-in
attributes are correct, or contain the correct type of information. This
visitor also checks that an attribute is allowed to be used in the current
particular context.
---
 gcc/rust/util/rust-attributes.cc | 839 +++++++++++++++++++++++++++++++
 gcc/rust/util/rust-attributes.h  | 270 ++++++++++
 2 files changed, 1109 insertions(+)
 create mode 100644 gcc/rust/util/rust-attributes.cc
 create mode 100644 gcc/rust/util/rust-attributes.h
  

Patch

diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc
new file mode 100644
index 00000000000..bf4bb2fbfe9
--- /dev/null
+++ b/gcc/rust/util/rust-attributes.cc
@@ -0,0 +1,839 @@ 
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-attributes.h"
+#include "rust-ast.h"
+#include "rust-ast-full.h"
+#include "rust-diagnostics.h"
+#include "safe-ctype.h"
+
+namespace Rust {
+namespace Analysis {
+
+// https://doc.rust-lang.org/stable/nightly-rustc/src/rustc_feature/builtin_attrs.rs.html#248
+static const BuiltinAttrDefinition __definitions[] = {
+  {"inline", CODE_GENERATION},
+  {"cold", CODE_GENERATION},
+  {"cfg", EXPANSION},
+  {"cfg_attr", EXPANSION},
+  {"deprecated", STATIC_ANALYSIS},
+  {"allow", STATIC_ANALYSIS},
+  {"doc", HIR_LOWERING},
+  {"must_use", STATIC_ANALYSIS},
+  {"lang", HIR_LOWERING},
+  {"link_section", CODE_GENERATION},
+  {"no_mangle", CODE_GENERATION},
+  {"repr", CODE_GENERATION},
+  {"path", EXPANSION},
+};
+
+BuiltinAttributeMappings *
+BuiltinAttributeMappings::get ()
+{
+  static BuiltinAttributeMappings *instance = nullptr;
+  if (instance == nullptr)
+    instance = new BuiltinAttributeMappings ();
+
+  return instance;
+}
+
+const BuiltinAttrDefinition &
+BuiltinAttributeMappings::lookup_builtin (const std::string &attr_name) const
+{
+  auto it = mappings.find (attr_name);
+  if (it == mappings.end ())
+    return BuiltinAttrDefinition::error_node ();
+
+  return it->second;
+}
+
+BuiltinAttributeMappings::BuiltinAttributeMappings ()
+{
+  size_t ndefinitions = sizeof (__definitions) / sizeof (BuiltinAttrDefinition);
+  for (size_t i = 0; i < ndefinitions; i++)
+    {
+      const BuiltinAttrDefinition &def = __definitions[i];
+      mappings.insert ({def.name, def});
+    }
+}
+
+AttributeChecker::AttributeChecker () {}
+
+void
+AttributeChecker::go (AST::Crate &crate)
+{
+  check_attributes (crate.get_inner_attrs ());
+
+  for (auto &item : crate.items)
+    item->accept_vis (*this);
+}
+
+static bool
+is_builtin (const AST::Attribute &attribute, BuiltinAttrDefinition &builtin)
+{
+  auto &segments = attribute.get_path ().get_segments ();
+
+  // Builtin attributes always have a single segment. This avoids us creating
+  // strings all over the place and performing a linear search in the builtins
+  // map
+  if (segments.size () != 1)
+    return false;
+
+  builtin = BuiltinAttributeMappings::get ()->lookup_builtin (
+    segments.at (0).get_segment_name ());
+
+  return !builtin.is_error ();
+}
+
+/**
+ * Check that the string given to #[doc(alias = ...)] or #[doc(alias(...))] is
+ * valid.
+ *
+ * This means no whitespace characters other than spaces and no quoting
+ * characters.
+ */
+static void
+check_doc_alias (const std::string &alias_input, const Location &locus)
+{
+  // FIXME: The locus here is for the whole attribute. Can we get the locus
+  // of the alias input instead?
+  for (auto c : alias_input)
+    if ((ISSPACE (c) && c != ' ') || c == '\'' || c == '\"')
+      {
+	auto to_print = std::string (1, c);
+	switch (c)
+	  {
+	  case '\n':
+	    to_print = "\\n";
+	    break;
+	  case '\t':
+	    to_print = "\\t";
+	    break;
+	  default:
+	    break;
+	  }
+	rust_error_at (locus,
+		       "invalid character used in %<#[doc(alias)]%> input: %qs",
+		       to_print.c_str ());
+      }
+
+  if (alias_input.empty ())
+    return;
+
+  if (alias_input.front () == ' ' || alias_input.back () == ' ')
+    rust_error_at (locus,
+		   "%<#[doc(alias)]%> input cannot start or end with a space");
+}
+
+static void
+check_doc_attribute (const AST::Attribute &attribute)
+{
+  if (!attribute.has_attr_input ())
+    {
+      rust_error_at (
+	attribute.get_locus (),
+	// FIXME: Improve error message here. Rustc has a very good one
+	"%<#[doc]%> cannot be an empty attribute");
+      return;
+    }
+
+  switch (attribute.get_attr_input ().get_attr_input_type ())
+    {
+    case AST::AttrInput::LITERAL:
+    case AST::AttrInput::META_ITEM:
+      break;
+      // FIXME: Handle them as well
+
+      case AST::AttrInput::TOKEN_TREE: {
+	// FIXME: This doesn't check for #[doc(alias(...))]
+	const auto &option = static_cast<const AST::DelimTokenTree &> (
+	  attribute.get_attr_input ());
+	auto *meta_item = option.parse_to_meta_item ();
+
+	for (auto &item : meta_item->get_items ())
+	  {
+	    if (item->is_key_value_pair ())
+	      {
+		auto name_value
+		  = static_cast<AST::MetaNameValueStr *> (item.get ())
+		      ->get_name_value_pair ();
+
+		// FIXME: Check for other stuff than #[doc(alias = ...)]
+		if (name_value.first == "alias")
+		  check_doc_alias (name_value.second, attribute.get_locus ());
+	      }
+	  }
+	break;
+      }
+    }
+}
+
+void
+AttributeChecker::check_attribute (const AST::Attribute &attribute)
+{
+  BuiltinAttrDefinition result;
+
+  // This checker does not check non-builtin attributes
+  if (!is_builtin (attribute, result))
+    return;
+
+  // TODO: Add checks here for each builtin attribute
+  // TODO: Have an enum of builtins as well, switching on strings is annoying
+  // and costly
+  if (result.name == "doc")
+    check_doc_attribute (attribute);
+}
+
+void
+AttributeChecker::check_attributes (const AST::AttrVec &attributes)
+{
+  for (auto &attr : attributes)
+    check_attribute (attr);
+}
+
+void
+AttributeChecker::visit (AST::Token &tok)
+{}
+
+void
+AttributeChecker::visit (AST::DelimTokenTree &delim_tok_tree)
+{}
+
+void
+AttributeChecker::visit (AST::AttrInputMetaItemContainer &input)
+{}
+
+void
+AttributeChecker::visit (AST::IdentifierExpr &ident_expr)
+{}
+
+void
+AttributeChecker::visit (AST::Lifetime &lifetime)
+{}
+
+void
+AttributeChecker::visit (AST::LifetimeParam &lifetime_param)
+{}
+
+void
+AttributeChecker::visit (AST::ConstGenericParam &const_param)
+{}
+
+// rust-path.h
+void
+AttributeChecker::visit (AST::PathInExpression &path)
+{}
+
+void
+AttributeChecker::visit (AST::TypePathSegment &segment)
+{}
+
+void
+AttributeChecker::visit (AST::TypePathSegmentGeneric &segment)
+{}
+
+void
+AttributeChecker::visit (AST::TypePathSegmentFunction &segment)
+{}
+
+void
+AttributeChecker::visit (AST::TypePath &path)
+{}
+
+void
+AttributeChecker::visit (AST::QualifiedPathInExpression &path)
+{}
+
+void
+AttributeChecker::visit (AST::QualifiedPathInType &path)
+{}
+
+// rust-expr.h
+void
+AttributeChecker::visit (AST::LiteralExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::AttrInputLiteral &attr_input)
+{}
+
+void
+AttributeChecker::visit (AST::MetaItemLitExpr &meta_item)
+{}
+
+void
+AttributeChecker::visit (AST::MetaItemPathLit &meta_item)
+{}
+
+void
+AttributeChecker::visit (AST::BorrowExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::DereferenceExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::ErrorPropagationExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::NegationExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::ArithmeticOrLogicalExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::ComparisonExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::LazyBooleanExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::TypeCastExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::AssignmentExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::CompoundAssignmentExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::GroupedExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::ArrayElemsValues &elems)
+{}
+
+void
+AttributeChecker::visit (AST::ArrayElemsCopied &elems)
+{}
+
+void
+AttributeChecker::visit (AST::ArrayExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::ArrayIndexExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::TupleExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::TupleIndexExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::StructExprStruct &expr)
+{}
+
+void
+AttributeChecker::visit (AST::StructExprFieldIdentifier &field)
+{}
+
+void
+AttributeChecker::visit (AST::StructExprFieldIdentifierValue &field)
+{}
+
+void
+AttributeChecker::visit (AST::StructExprFieldIndexValue &field)
+{}
+
+void
+AttributeChecker::visit (AST::StructExprStructFields &expr)
+{}
+
+void
+AttributeChecker::visit (AST::StructExprStructBase &expr)
+{}
+
+void
+AttributeChecker::visit (AST::CallExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::MethodCallExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::FieldAccessExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::ClosureExprInner &expr)
+{}
+
+void
+AttributeChecker::visit (AST::BlockExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::ClosureExprInnerTyped &expr)
+{}
+
+void
+AttributeChecker::visit (AST::ContinueExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::BreakExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::RangeFromToExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::RangeFromExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::RangeToExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::RangeFullExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::RangeFromToInclExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::RangeToInclExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::ReturnExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::UnsafeBlockExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::LoopExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::WhileLoopExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::WhileLetLoopExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::ForLoopExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::IfExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::IfExprConseqElse &expr)
+{}
+
+void
+AttributeChecker::visit (AST::IfExprConseqIf &expr)
+{}
+
+void
+AttributeChecker::visit (AST::IfExprConseqIfLet &expr)
+{}
+
+void
+AttributeChecker::visit (AST::IfLetExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::IfLetExprConseqElse &expr)
+{}
+
+void
+AttributeChecker::visit (AST::IfLetExprConseqIf &expr)
+{}
+
+void
+AttributeChecker::visit (AST::IfLetExprConseqIfLet &expr)
+{}
+
+void
+AttributeChecker::visit (AST::MatchExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::AwaitExpr &expr)
+{}
+
+void
+AttributeChecker::visit (AST::AsyncBlockExpr &expr)
+{}
+
+// rust-item.h
+void
+AttributeChecker::visit (AST::TypeParam &param)
+{}
+
+void
+AttributeChecker::visit (AST::LifetimeWhereClauseItem &item)
+{}
+
+void
+AttributeChecker::visit (AST::TypeBoundWhereClauseItem &item)
+{}
+
+void
+AttributeChecker::visit (AST::Method &method)
+{}
+
+void
+AttributeChecker::visit (AST::Module &module)
+{}
+
+void
+AttributeChecker::visit (AST::ExternCrate &crate)
+{}
+
+void
+AttributeChecker::visit (AST::UseTreeGlob &use_tree)
+{}
+
+void
+AttributeChecker::visit (AST::UseTreeList &use_tree)
+{}
+
+void
+AttributeChecker::visit (AST::UseTreeRebind &use_tree)
+{}
+
+void
+AttributeChecker::visit (AST::UseDeclaration &use_decl)
+{}
+
+void
+AttributeChecker::visit (AST::Function &function)
+{}
+
+void
+AttributeChecker::visit (AST::TypeAlias &type_alias)
+{}
+
+void
+AttributeChecker::visit (AST::StructStruct &struct_item)
+{
+  check_attributes (struct_item.get_outer_attrs ());
+}
+
+void
+AttributeChecker::visit (AST::TupleStruct &tuple_struct)
+{}
+
+void
+AttributeChecker::visit (AST::EnumItem &item)
+{}
+
+void
+AttributeChecker::visit (AST::EnumItemTuple &item)
+{}
+
+void
+AttributeChecker::visit (AST::EnumItemStruct &item)
+{}
+
+void
+AttributeChecker::visit (AST::EnumItemDiscriminant &item)
+{}
+
+void
+AttributeChecker::visit (AST::Enum &enum_item)
+{}
+
+void
+AttributeChecker::visit (AST::Union &union_item)
+{}
+
+void
+AttributeChecker::visit (AST::ConstantItem &const_item)
+{}
+
+void
+AttributeChecker::visit (AST::StaticItem &static_item)
+{}
+
+void
+AttributeChecker::visit (AST::TraitItemFunc &item)
+{}
+
+void
+AttributeChecker::visit (AST::TraitItemMethod &item)
+{}
+
+void
+AttributeChecker::visit (AST::TraitItemConst &item)
+{}
+
+void
+AttributeChecker::visit (AST::TraitItemType &item)
+{}
+
+void
+AttributeChecker::visit (AST::Trait &trait)
+{}
+
+void
+AttributeChecker::visit (AST::InherentImpl &impl)
+{}
+
+void
+AttributeChecker::visit (AST::TraitImpl &impl)
+{}
+
+void
+AttributeChecker::visit (AST::ExternalStaticItem &item)
+{}
+
+void
+AttributeChecker::visit (AST::ExternalFunctionItem &item)
+{}
+
+void
+AttributeChecker::visit (AST::ExternBlock &block)
+{}
+
+// rust-macro.h
+void
+AttributeChecker::visit (AST::MacroMatchFragment &match)
+{}
+
+void
+AttributeChecker::visit (AST::MacroMatchRepetition &match)
+{}
+
+void
+AttributeChecker::visit (AST::MacroMatcher &matcher)
+{}
+
+void
+AttributeChecker::visit (AST::MacroRulesDefinition &rules_def)
+{}
+
+void
+AttributeChecker::visit (AST::MacroInvocation &macro_invoc)
+{}
+
+void
+AttributeChecker::visit (AST::MetaItemPath &meta_item)
+{}
+
+void
+AttributeChecker::visit (AST::MetaItemSeq &meta_item)
+{}
+
+void
+AttributeChecker::visit (AST::MetaWord &meta_item)
+{}
+
+void
+AttributeChecker::visit (AST::MetaNameValueStr &meta_item)
+{}
+
+void
+AttributeChecker::visit (AST::MetaListPaths &meta_item)
+{}
+
+void
+AttributeChecker::visit (AST::MetaListNameValueStr &meta_item)
+{}
+
+// rust-pattern.h
+void
+AttributeChecker::visit (AST::LiteralPattern &pattern)
+{}
+
+void
+AttributeChecker::visit (AST::IdentifierPattern &pattern)
+{}
+
+void
+AttributeChecker::visit (AST::WildcardPattern &pattern)
+{}
+
+// void AttributeChecker::visit(RangePatternBound& bound){}
+
+void
+AttributeChecker::visit (AST::RangePatternBoundLiteral &bound)
+{}
+
+void
+AttributeChecker::visit (AST::RangePatternBoundPath &bound)
+{}
+
+void
+AttributeChecker::visit (AST::RangePatternBoundQualPath &bound)
+{}
+
+void
+AttributeChecker::visit (AST::RangePattern &pattern)
+{}
+
+void
+AttributeChecker::visit (AST::ReferencePattern &pattern)
+{}
+
+// void AttributeChecker::visit(StructPatternField& field){}
+
+void
+AttributeChecker::visit (AST::StructPatternFieldTuplePat &field)
+{}
+
+void
+AttributeChecker::visit (AST::StructPatternFieldIdentPat &field)
+{}
+
+void
+AttributeChecker::visit (AST::StructPatternFieldIdent &field)
+{}
+
+void
+AttributeChecker::visit (AST::StructPattern &pattern)
+{}
+
+// void AttributeChecker::visit(TupleStructItems& tuple_items){}
+
+void
+AttributeChecker::visit (AST::TupleStructItemsNoRange &tuple_items)
+{}
+
+void
+AttributeChecker::visit (AST::TupleStructItemsRange &tuple_items)
+{}
+
+void
+AttributeChecker::visit (AST::TupleStructPattern &pattern)
+{}
+
+// void AttributeChecker::visit(TuplePatternItems& tuple_items){}
+
+void
+AttributeChecker::visit (AST::TuplePatternItemsMultiple &tuple_items)
+{}
+
+void
+AttributeChecker::visit (AST::TuplePatternItemsRanged &tuple_items)
+{}
+
+void
+AttributeChecker::visit (AST::TuplePattern &pattern)
+{}
+
+void
+AttributeChecker::visit (AST::GroupedPattern &pattern)
+{}
+
+void
+AttributeChecker::visit (AST::SlicePattern &pattern)
+{}
+
+// rust-stmt.h
+void
+AttributeChecker::visit (AST::EmptyStmt &stmt)
+{}
+
+void
+AttributeChecker::visit (AST::LetStmt &stmt)
+{}
+
+void
+AttributeChecker::visit (AST::ExprStmtWithoutBlock &stmt)
+{}
+
+void
+AttributeChecker::visit (AST::ExprStmtWithBlock &stmt)
+{}
+
+// rust-type.h
+void
+AttributeChecker::visit (AST::TraitBound &bound)
+{}
+
+void
+AttributeChecker::visit (AST::ImplTraitType &type)
+{}
+
+void
+AttributeChecker::visit (AST::TraitObjectType &type)
+{}
+
+void
+AttributeChecker::visit (AST::ParenthesisedType &type)
+{}
+
+void
+AttributeChecker::visit (AST::ImplTraitTypeOneBound &type)
+{}
+
+void
+AttributeChecker::visit (AST::TraitObjectTypeOneBound &type)
+{}
+
+void
+AttributeChecker::visit (AST::TupleType &type)
+{}
+
+void
+AttributeChecker::visit (AST::NeverType &type)
+{}
+
+void
+AttributeChecker::visit (AST::RawPointerType &type)
+{}
+
+void
+AttributeChecker::visit (AST::ReferenceType &type)
+{}
+
+void
+AttributeChecker::visit (AST::ArrayType &type)
+{}
+
+void
+AttributeChecker::visit (AST::SliceType &type)
+{}
+
+void
+AttributeChecker::visit (AST::InferredType &type)
+{}
+
+void
+AttributeChecker::visit (AST::BareFunctionType &type)
+{}
+
+} // namespace Analysis
+} // namespace Rust
diff --git a/gcc/rust/util/rust-attributes.h b/gcc/rust/util/rust-attributes.h
new file mode 100644
index 00000000000..3ac93ff5908
--- /dev/null
+++ b/gcc/rust/util/rust-attributes.h
@@ -0,0 +1,270 @@ 
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast.h"
+#include "rust-system.h"
+#include "rust-ast-visitor.h"
+
+namespace Rust {
+namespace Analysis {
+
+enum CompilerPass
+{
+  UNKNOWN,
+
+  EXPANSION,
+  NAME_RESOLUTION,
+  HIR_LOWERING,
+  TYPE_CHECK,
+  STATIC_ANALYSIS,
+  CODE_GENERATION
+};
+
+struct BuiltinAttrDefinition
+{
+  std::string name;
+  CompilerPass handler;
+
+  static BuiltinAttrDefinition get_error ()
+  {
+    return BuiltinAttrDefinition{"", UNKNOWN};
+  }
+
+  static BuiltinAttrDefinition &error_node ()
+  {
+    static BuiltinAttrDefinition error_node = get_error ();
+    return error_node;
+  }
+
+  bool is_error () const { return name.empty (); }
+};
+
+class BuiltinAttributeMappings
+{
+public:
+  static BuiltinAttributeMappings *get ();
+
+  const BuiltinAttrDefinition &
+  lookup_builtin (const std::string &attr_name) const;
+
+private:
+  BuiltinAttributeMappings ();
+
+  std::map<std::string, const BuiltinAttrDefinition> mappings;
+};
+
+/**
+ * Checks the validity of various attributes. The goal of this visitor is to
+ * make sure that attributes are applied in allowed contexts, for example to
+ * make sure that #[inline] is only applied to functions and closures, as well
+ * as checking the "arguments" or input given to these attributes, making sure
+ * it is appropriate and valid.
+ */
+class AttributeChecker : public AST::ASTVisitor
+{
+public:
+  AttributeChecker ();
+
+  /**
+   * Check all the attributes of all the items of a crate
+   */
+  void go (AST::Crate &crate);
+
+private:
+  /* Check the validity of a given attribute */
+  void check_attribute (const AST::Attribute &attribute);
+
+  /* Check the validity of all given attributes */
+  void check_attributes (const AST::AttrVec &attributes);
+
+  // rust-ast.h
+  void visit (AST::Token &tok);
+  void visit (AST::DelimTokenTree &delim_tok_tree);
+  void visit (AST::AttrInputMetaItemContainer &input);
+  void visit (AST::IdentifierExpr &ident_expr);
+  void visit (AST::Lifetime &lifetime);
+  void visit (AST::LifetimeParam &lifetime_param);
+  void visit (AST::ConstGenericParam &const_param);
+
+  // rust-path.h
+  void visit (AST::PathInExpression &path);
+  void visit (AST::TypePathSegment &segment);
+  void visit (AST::TypePathSegmentGeneric &segment);
+  void visit (AST::TypePathSegmentFunction &segment);
+  void visit (AST::TypePath &path);
+  void visit (AST::QualifiedPathInExpression &path);
+  void visit (AST::QualifiedPathInType &path);
+
+  // rust-expr.h
+  void visit (AST::LiteralExpr &expr);
+  void visit (AST::AttrInputLiteral &attr_input);
+  void visit (AST::MetaItemLitExpr &meta_item);
+  void visit (AST::MetaItemPathLit &meta_item);
+  void visit (AST::BorrowExpr &expr);
+  void visit (AST::DereferenceExpr &expr);
+  void visit (AST::ErrorPropagationExpr &expr);
+  void visit (AST::NegationExpr &expr);
+  void visit (AST::ArithmeticOrLogicalExpr &expr);
+  void visit (AST::ComparisonExpr &expr);
+  void visit (AST::LazyBooleanExpr &expr);
+  void visit (AST::TypeCastExpr &expr);
+  void visit (AST::AssignmentExpr &expr);
+  void visit (AST::CompoundAssignmentExpr &expr);
+  void visit (AST::GroupedExpr &expr);
+  void visit (AST::ArrayElemsValues &elems);
+  void visit (AST::ArrayElemsCopied &elems);
+  void visit (AST::ArrayExpr &expr);
+  void visit (AST::ArrayIndexExpr &expr);
+  void visit (AST::TupleExpr &expr);
+  void visit (AST::TupleIndexExpr &expr);
+  void visit (AST::StructExprStruct &expr);
+  void visit (AST::StructExprFieldIdentifier &field);
+  void visit (AST::StructExprFieldIdentifierValue &field);
+  void visit (AST::StructExprFieldIndexValue &field);
+  void visit (AST::StructExprStructFields &expr);
+  void visit (AST::StructExprStructBase &expr);
+  void visit (AST::CallExpr &expr);
+  void visit (AST::MethodCallExpr &expr);
+  void visit (AST::FieldAccessExpr &expr);
+  void visit (AST::ClosureExprInner &expr);
+  void visit (AST::BlockExpr &expr);
+  void visit (AST::ClosureExprInnerTyped &expr);
+  void visit (AST::ContinueExpr &expr);
+  void visit (AST::BreakExpr &expr);
+  void visit (AST::RangeFromToExpr &expr);
+  void visit (AST::RangeFromExpr &expr);
+  void visit (AST::RangeToExpr &expr);
+  void visit (AST::RangeFullExpr &expr);
+  void visit (AST::RangeFromToInclExpr &expr);
+  void visit (AST::RangeToInclExpr &expr);
+  void visit (AST::ReturnExpr &expr);
+  void visit (AST::UnsafeBlockExpr &expr);
+  void visit (AST::LoopExpr &expr);
+  void visit (AST::WhileLoopExpr &expr);
+  void visit (AST::WhileLetLoopExpr &expr);
+  void visit (AST::ForLoopExpr &expr);
+  void visit (AST::IfExpr &expr);
+  void visit (AST::IfExprConseqElse &expr);
+  void visit (AST::IfExprConseqIf &expr);
+  void visit (AST::IfExprConseqIfLet &expr);
+  void visit (AST::IfLetExpr &expr);
+  void visit (AST::IfLetExprConseqElse &expr);
+  void visit (AST::IfLetExprConseqIf &expr);
+  void visit (AST::IfLetExprConseqIfLet &expr);
+  void visit (AST::MatchExpr &expr);
+  void visit (AST::AwaitExpr &expr);
+  void visit (AST::AsyncBlockExpr &expr);
+
+  // rust-item.h
+  void visit (AST::TypeParam &param);
+  void visit (AST::LifetimeWhereClauseItem &item);
+  void visit (AST::TypeBoundWhereClauseItem &item);
+  void visit (AST::Method &method);
+  void visit (AST::Module &module);
+  void visit (AST::ExternCrate &crate);
+  void visit (AST::UseTreeGlob &use_tree);
+  void visit (AST::UseTreeList &use_tree);
+  void visit (AST::UseTreeRebind &use_tree);
+  void visit (AST::UseDeclaration &use_decl);
+  void visit (AST::Function &function);
+  void visit (AST::TypeAlias &type_alias);
+  void visit (AST::StructStruct &struct_item);
+  void visit (AST::TupleStruct &tuple_struct);
+  void visit (AST::EnumItem &item);
+  void visit (AST::EnumItemTuple &item);
+  void visit (AST::EnumItemStruct &item);
+  void visit (AST::EnumItemDiscriminant &item);
+  void visit (AST::Enum &enum_item);
+  void visit (AST::Union &union_item);
+  void visit (AST::ConstantItem &const_item);
+  void visit (AST::StaticItem &static_item);
+  void visit (AST::TraitItemFunc &item);
+  void visit (AST::TraitItemMethod &item);
+  void visit (AST::TraitItemConst &item);
+  void visit (AST::TraitItemType &item);
+  void visit (AST::Trait &trait);
+  void visit (AST::InherentImpl &impl);
+  void visit (AST::TraitImpl &impl);
+  void visit (AST::ExternalStaticItem &item);
+  void visit (AST::ExternalFunctionItem &item);
+  void visit (AST::ExternBlock &block);
+
+  // rust-macro.h
+  void visit (AST::MacroMatchFragment &match);
+  void visit (AST::MacroMatchRepetition &match);
+  void visit (AST::MacroMatcher &matcher);
+  void visit (AST::MacroRulesDefinition &rules_def);
+  void visit (AST::MacroInvocation &macro_invoc);
+  void visit (AST::MetaItemPath &meta_item);
+  void visit (AST::MetaItemSeq &meta_item);
+  void visit (AST::MetaWord &meta_item);
+  void visit (AST::MetaNameValueStr &meta_item);
+  void visit (AST::MetaListPaths &meta_item);
+  void visit (AST::MetaListNameValueStr &meta_item);
+
+  // rust-pattern.h
+  void visit (AST::LiteralPattern &pattern);
+  void visit (AST::IdentifierPattern &pattern);
+  void visit (AST::WildcardPattern &pattern);
+  // void visit(RangePatternBound& bound);
+  void visit (AST::RangePatternBoundLiteral &bound);
+  void visit (AST::RangePatternBoundPath &bound);
+  void visit (AST::RangePatternBoundQualPath &bound);
+  void visit (AST::RangePattern &pattern);
+  void visit (AST::ReferencePattern &pattern);
+  // void visit(StructPatternField& field);
+  void visit (AST::StructPatternFieldTuplePat &field);
+  void visit (AST::StructPatternFieldIdentPat &field);
+  void visit (AST::StructPatternFieldIdent &field);
+  void visit (AST::StructPattern &pattern);
+  // void visit(TupleStructItems& tuple_items);
+  void visit (AST::TupleStructItemsNoRange &tuple_items);
+  void visit (AST::TupleStructItemsRange &tuple_items);
+  void visit (AST::TupleStructPattern &pattern);
+  // void visit(TuplePatternItems& tuple_items);
+  void visit (AST::TuplePatternItemsMultiple &tuple_items);
+  void visit (AST::TuplePatternItemsRanged &tuple_items);
+  void visit (AST::TuplePattern &pattern);
+  void visit (AST::GroupedPattern &pattern);
+  void visit (AST::SlicePattern &pattern);
+
+  // rust-stmt.h
+  void visit (AST::EmptyStmt &stmt);
+  void visit (AST::LetStmt &stmt);
+  void visit (AST::ExprStmtWithoutBlock &stmt);
+  void visit (AST::ExprStmtWithBlock &stmt);
+
+  // rust-type.h
+  void visit (AST::TraitBound &bound);
+  void visit (AST::ImplTraitType &type);
+  void visit (AST::TraitObjectType &type);
+  void visit (AST::ParenthesisedType &type);
+  void visit (AST::ImplTraitTypeOneBound &type);
+  void visit (AST::TraitObjectTypeOneBound &type);
+  void visit (AST::TupleType &type);
+  void visit (AST::NeverType &type);
+  void visit (AST::RawPointerType &type);
+  void visit (AST::ReferenceType &type);
+  void visit (AST::ArrayType &type);
+  void visit (AST::SliceType &type);
+  void visit (AST::InferredType &type);
+  void visit (AST::BareFunctionType &type);
+};
+
+} // namespace Analysis
+} // namespace Rust