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
====================
// 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.
let Args = [EnumArgument<"DefaultState", "ConsumedState",
["unknown", "consumed", "unconsumed"],
["Unknown", "Consumed", "Unconsumed"]>];
- let Documentation = [Undocumented];
+ let Documentation = [ConsumableDocs];
}
def ConsumableAutoCast : InheritableAttr {
let Args = [VariadicEnumArgument<"CallableState", "ConsumedState",
["unknown", "consumed", "unconsumed"],
["Unknown", "Consumed", "Unconsumed"]>];
- let Documentation = [Undocumented];
+ let Documentation = [CallableWhenDocs];
}
def ParamTypestate : InheritableAttr {
let Args = [EnumArgument<"ParamState", "ConsumedState",
["unknown", "consumed", "unconsumed"],
["Unknown", "Consumed", "Unconsumed"]>];
- let Documentation = [Undocumented];
+ let Documentation = [ParamTypestateDocs];
}
def ReturnTypestate : InheritableAttr {
let Args = [EnumArgument<"State", "ConsumedState",
["unknown", "consumed", "unconsumed"],
["Unknown", "Consumed", "Unconsumed"]>];
- let Documentation = [Undocumented];
+ let Documentation = [ReturnTypestateDocs];
}
def SetTypestate : InheritableAttr {
let Args = [EnumArgument<"NewState", "ConsumedState",
["unknown", "consumed", "unconsumed"],
["Unknown", "Consumed", "Unconsumed"]>];
- let Documentation = [Undocumented];
+ let Documentation = [SetTypestateDocs];
}
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.
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``.
+ }];
+}
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 {
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;
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));
}
}