]> granicus.if.org Git - clang/commitdiff
Refactored the way attribute category headers are handled so that it is possible...
authorAaron Ballman <aaron@aaronballman.com>
Wed, 19 Feb 2014 22:59:32 +0000 (22:59 +0000)
committerAaron Ballman <aaron@aaronballman.com>
Wed, 19 Feb 2014 22:59:32 +0000 (22:59 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201732 91177308-0d34-0410-b5e6-96231b3b80d8

docs/LanguageExtensions.rst
include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
utils/TableGen/ClangAttrEmitter.cpp

index 457b0a386b35c55cce476bff2dd596f69e0af342..be80a7640ffd642f2a673a5c460e2477cfb05d2f 100644 (file)
@@ -1697,64 +1697,6 @@ The complete list of thread safety attributes, along with examples and
 frequently asked questions, can be found in the main documentation: see 
 :doc:`ThreadSafetyAnalysis`.
 
-
-Consumed Annotation Checking
-============================
-
-Clang supports additional attributes for checking basic resource management
-properties, specifically for unique objects that have a single owning reference.
-The following attributes are currently supported, although **the implementation
-for these annotations is currently in development and are subject to change.**
-
-``consumable``
---------------
-
-Each class that uses any of the following annotations must first be marked
-using the consumable attribute.  Failure to do so will result in a warning.
-
-``set_typestate(new_state)``
-----------------------------
-
-Annotate methods that transition an object into a new state with
-``__attribute__((set_typestate(new_state)))``.  The new new state must be
-unconsumed, consumed, or unknown.
-
-``callable_when(...)``
-----------------------
-
-Use ``__attribute__((callable_when(...)))`` to indicate what states a method
-may be called in.  Valid states are unconsumed, consumed, or unknown.  Each
-argument to this attribute must be a quoted string.  E.g.:
-
-``__attribute__((callable_when("unconsumed", "unknown")))``
-
-``tests_typestate(tested_state)``
----------------------------------
-
-Use ``__attribute__((tests_typestate(tested_state)))`` to indicate that a method
-returns true if the object is in the specified state..
-
-``param_typestate(expected_state)``
------------------------------------
-
-This attribute specifies expectations about function parameters.  Calls to an
-function with annotated parameters will issue a warning if the corresponding
-argument isn't in the expected state.  The attribute is also used to set the
-initial state of the parameter when analyzing the function's body.
-
-``return_typestate(ret_state)``
--------------------------------
-
-The ``return_typestate`` attribute can be applied to functions or parameters.
-When applied to a function the attribute specifies the state of the returned
-value.  The function's body is checked to ensure that it always returns a value
-in the specified state.  On the caller side, values returned by the annotated
-function are initialized to the given state.
-
-If the attribute is applied to a function parameter it modifies the state of
-an argument after a call to the function returns.  The function's body is
-checked to ensure that the parameter is in the expected state before returning. 
-
 Type Safety Checking
 ====================
 
index 65702146256ccd679e1777fbb575c3f3ed2eb3b4..922dfa53feea23bca3ee4c33aa18823e91621d86 100644 (file)
 // specific documentation that is collated within the larger document.
 class DocumentationCategory<string name> {
   string Name = name;
+  code Content = [{}];
 }
-def DocCatFunction : DocumentationCategory<"Functions">;
-def DocCatVariable : DocumentationCategory<"Variables">;
-def DocCatType : DocumentationCategory<"Types">;
-def DocCatStmt : DocumentationCategory<"Statements">;
+def DocCatFunction : DocumentationCategory<"Function Attributes">;
+def DocCatVariable : DocumentationCategory<"Variable Attributes">;
+def DocCatType : DocumentationCategory<"Type Attributes">;
+def DocCatStmt : DocumentationCategory<"Statement Attributes">;
 // Attributes listed under the Undocumented category do not generate any public
 // documentation. Ideally, this category should be used for internal-only
 // attributes which contain no spellings.
@@ -1484,7 +1485,7 @@ def Consumable : InheritableAttr {
   let Args = [EnumArgument<"DefaultState", "ConsumedState",
                            ["unknown", "consumed", "unconsumed"],
                            ["Unknown", "Consumed", "Unconsumed"]>];
-  let Documentation = [Undocumented];
+  let Documentation = [ConsumableDocs];
 }
 
 def ConsumableAutoCast : InheritableAttr {
@@ -1505,7 +1506,7 @@ def CallableWhen : InheritableAttr {
   let Args = [VariadicEnumArgument<"CallableState", "ConsumedState",
                                    ["unknown", "consumed", "unconsumed"],
                                    ["Unknown", "Consumed", "Unconsumed"]>];
-  let Documentation = [Undocumented];
+  let Documentation = [CallableWhenDocs];
 }
 
 def ParamTypestate : InheritableAttr {
@@ -1514,7 +1515,7 @@ def ParamTypestate : InheritableAttr {
   let Args = [EnumArgument<"ParamState", "ConsumedState",
                            ["unknown", "consumed", "unconsumed"],
                            ["Unknown", "Consumed", "Unconsumed"]>];
-  let Documentation = [Undocumented];
+  let Documentation = [ParamTypestateDocs];
 }
 
 def ReturnTypestate : InheritableAttr {
@@ -1523,7 +1524,7 @@ def ReturnTypestate : InheritableAttr {
   let Args = [EnumArgument<"State", "ConsumedState",
                            ["unknown", "consumed", "unconsumed"],
                            ["Unknown", "Consumed", "Unconsumed"]>];
-  let Documentation = [Undocumented];
+  let Documentation = [ReturnTypestateDocs];
 }
 
 def SetTypestate : InheritableAttr {
@@ -1532,7 +1533,7 @@ def SetTypestate : InheritableAttr {
   let Args = [EnumArgument<"NewState", "ConsumedState",
                            ["unknown", "consumed", "unconsumed"],
                            ["Unknown", "Consumed", "Unconsumed"]>];
-  let Documentation = [Undocumented];
+  let Documentation = [SetTypestateDocs];
 }
 
 def TestTypestate : InheritableAttr {
@@ -1541,7 +1542,7 @@ def TestTypestate : InheritableAttr {
   let Args = [EnumArgument<"TestState", "ConsumedState",
                            ["consumed", "unconsumed"],
                            ["Consumed", "Unconsumed"]>];
-  let Documentation = [Undocumented];
+  let Documentation = [TestTypestateDocs];
 }
 
 // Type safety attributes for `void *' pointers and type tags.
index 69cba427c1caac23ea0378975448e84c52a3a31a..e344946d9d21e5f6a8734cdd4cb8046559e34304 100644 (file)
@@ -498,3 +498,76 @@ The semantics are as follows:
   a sequence equivalent to "movs pc, lr" will be used.
   }];
 }
+
+def DocCatConsumed : DocumentationCategory<"Consumed Annotation Checking"> {
+  let Content = [{
+Clang supports additional attributes for checking basic resource management
+properties, specifically for unique objects that have a single owning reference.
+The following attributes are currently supported, although **the implementation
+for these annotations is currently in development and are subject to change.**
+  }];
+}
+
+def SetTypestateDocs : Documentation {
+  let Category = DocCatConsumed;
+  let Content = [{
+Annotate methods that transition an object into a new state with
+``__attribute__((set_typestate(new_state)))``.  The new new state must be
+unconsumed, consumed, or unknown.
+  }];
+}
+
+def CallableWhenDocs : Documentation {
+  let Category = DocCatConsumed;
+  let Content = [{
+Use ``__attribute__((callable_when(...)))`` to indicate what states a method
+may be called in.  Valid states are unconsumed, consumed, or unknown.  Each
+argument to this attribute must be a quoted string.  E.g.:
+
+``__attribute__((callable_when("unconsumed", "unknown")))``
+  }];
+}
+
+def TestTypestateDocs : Documentation {
+  let Category = DocCatConsumed;
+  let Content = [{
+Use ``__attribute__((test_typestate(tested_state)))`` to indicate that a method
+returns true if the object is in the specified state..
+  }];
+}
+
+def ParamTypestateDocs : Documentation {
+  let Category = DocCatConsumed;
+  let Content = [{
+This attribute specifies expectations about function parameters.  Calls to an
+function with annotated parameters will issue a warning if the corresponding
+argument isn't in the expected state.  The attribute is also used to set the
+initial state of the parameter when analyzing the function's body.
+  }];
+}
+
+def ReturnTypestateDocs : Documentation {
+  let Category = DocCatConsumed;
+  let Content = [{
+The ``return_typestate`` attribute can be applied to functions or parameters.
+When applied to a function the attribute specifies the state of the returned
+value.  The function's body is checked to ensure that it always returns a value
+in the specified state.  On the caller side, values returned by the annotated
+function are initialized to the given state.
+
+When applied to a function parameter it modifies the state of an argument after
+a call to the function returns.  The function's body is checked to ensure that
+the parameter is in the expected state before returning.
+  }];
+}
+
+def ConsumableDocs : Documentation {
+  let Category = DocCatConsumed;
+  let Content = [{
+Each ``class`` that uses any of the typestate annotations must first be marked
+using the ``consumable`` attribute.  Failure to do so will result in a warning.
+
+This attribute accepts a single parameter that must be one of the following:
+``unknown``, ``consumed``, or ``unconsumed``.
+  }];
+}
index 4c94e208a69beea659f3962b8c7848ce8efca5cd..8f65d910858669a89274886523444d3a6946a198 100644 (file)
@@ -2648,49 +2648,32 @@ void EmitClangAttrParserStringSwitches(RecordKeeper &Records,
 
 class DocumentationData {
 public:
-  enum DocCategory {
-    Function,
-    Variable,
-    Type,
-    Statement,
-    Undocumented
-  };
-
-  DocCategory Category;
   const Record *Documentation;
   const Record *Attribute;
 
-  DocumentationData(DocCategory Category, const Record &Documentation,
-                    const Record &Attribute)
-      : Category(Category), Documentation(&Documentation),
-        Attribute(&Attribute) {}
+  DocumentationData(const Record &Documentation, const Record &Attribute)
+      : Documentation(&Documentation), Attribute(&Attribute) {}
 };
 
-static void WriteCategoryHeader(DocumentationData::DocCategory Category,
+static void WriteCategoryHeader(const Record *DocCategory,
                                 raw_ostream &OS) {
-  OS << "\n";
-  switch (Category) {
-    case DocumentationData::Undocumented:
-      assert(false && "Undocumented attributes are not documented!");
-      break;
-    case DocumentationData::Function:
-      OS << "Function Attributes\n";
-      OS << "===================\n";
-      break;
-    case DocumentationData::Variable:
-      OS << "Variable Attributes\n";
-      OS << "===================\n";
-      break;
-    case DocumentationData::Type:
-      OS << "Type Attributes\n";
-      OS << "===============\n";
-      break;
-    case DocumentationData::Statement:
-      OS << "Statement Attributes\n";
-      OS << "====================\n";
-      break;
+  const std::string &Name = DocCategory->getValueAsString("Name");
+  OS << Name << "\n" << std::string(Name.length(), '=') << "\n";
+
+  // If there is content, print that as well.
+  std::string ContentStr = DocCategory->getValueAsString("Content");
+  if (!ContentStr.empty()) {
+    // Trim leading and trailing newlines and spaces.
+    StringRef Content(ContentStr);
+    while (Content.startswith("\r") || Content.startswith("\n") ||
+           Content.startswith(" ") || Content.startswith("\t"))
+           Content = Content.substr(1);
+    while (Content.endswith("\r") || Content.endswith("\n") ||
+           Content.endswith(" ") || Content.endswith("\t"))
+           Content = Content.substr(0, Content.size() - 1);
+    OS << Content;
   }
-  OS << "\n";
+  OS << "\n\n";
 }
 
 enum SpellingKind {
@@ -2828,9 +2811,9 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) {
     return;
   }
 
-  OS << Documentation->getValueAsString("Intro");
+  OS << Documentation->getValueAsString("Intro") << "\n";
 
-  typedef std::map<DocumentationData::DocCategory,
+  typedef std::map<const Record *,
                    std::vector<DocumentationData> > CategoryMap;
   CategoryMap SplitDocs;
 
@@ -2844,26 +2827,19 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) {
     for (std::vector<Record *>::const_iterator DI = Docs.begin(),
          DE = Docs.end(); DI != DE; ++DI) {
       const Record &Doc = **DI;
-      DocumentationData::DocCategory Cat =
-          StringSwitch<DocumentationData::DocCategory>(
-              Doc.getValueAsDef("Category")->getValueAsString("Name"))
-              .Case("Functions", DocumentationData::Function)
-              .Case("Variables", DocumentationData::Variable)
-              .Case("Types", DocumentationData::Type)
-              .Case("Statements", DocumentationData::Statement)
-              .Case("Undocumented", DocumentationData::Undocumented);
-
+      const Record *Category = Doc.getValueAsDef("Category");
       // If the category is "undocumented", then there cannot be any other
       // documentation categories (otherwise, the attribute would become
       // documented).
-      bool Undocumented = DocumentationData::Undocumented == Cat;
+      std::string Cat = Category->getValueAsString("Name");
+      bool Undocumented = Cat == "Undocumented";
       if (Undocumented && Docs.size() > 1)
         PrintFatalError(Doc.getLoc(),
                         "Attribute is \"Undocumented\", but has multiple "
                         "documentation categories");      
 
       if (!Undocumented)
-        SplitDocs[Cat].push_back(DocumentationData(Cat, Doc, Attr));
+        SplitDocs[Category].push_back(DocumentationData(Doc, Attr));
     }
   }