Clang AttributeReference: emit entries for "Undocumented" attributes.

Almost all attributes currently marked `Undocumented` are user-facing
attributes which _ought_ to be documented, but nobody has written it
yet. This change ensures that we at least acknowledge that these
attributes exist in the documentation, even if we have no description
of their semantics.

A new category, `InternalOnly` has been added for those few attributes
which are not user-facing, and should remain omitted from the docs.
This commit is contained in:
James Y Knight 2022-06-22 09:41:59 -04:00
parent cef65864af
commit 17e2702528
3 changed files with 67 additions and 44 deletions

View file

@ -2920,7 +2920,7 @@ that is named after the attribute being documented.
If the attribute is not for public consumption, or is an implicitly-created
attribute that has no visible spelling, the documentation list can specify the
``Undocumented`` object. Otherwise, the attribute should have its documentation
``InternalOnly`` object. Otherwise, the attribute should have its documentation
added to AttrDocs.td.
Documentation derives from the ``Documentation`` tablegen type. All derived

View file

@ -19,10 +19,19 @@ def DocCatType : DocumentationCategory<"Type Attributes">;
def DocCatStmt : DocumentationCategory<"Statement Attributes">;
def DocCatDecl : DocumentationCategory<"Declaration 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.
def DocCatUndocumented : DocumentationCategory<"Undocumented">;
// This category is for attributes which have not yet been properly documented,
// but should be.
def DocCatUndocumented : DocumentationCategory<"Undocumented"> {
let Content = [{
This section lists attributes which are recognized by Clang, but which are
currently missing documentation.
}];
}
// Attributes listed under the InternalOnly category do not generate any entry
// in the documentation. This category should be used only when we _want_
// to not document the attribute, e.g. if the attribute has no spellings.
def DocCatInternalOnly : DocumentationCategory<"InternalOnly">;
class DocDeprecated<string replacement = ""> {
// If the Replacement field is empty, no replacement will be listed with the
@ -48,11 +57,17 @@ class Documentation {
DocDeprecated Deprecated;
}
// Specifies that the attribute is explicitly undocumented. This can be a
// helpful placeholder for the attribute while working on the implementation,
// but should not be used once feature work has been completed.
// Specifies that the attribute is explicitly omitted from the documentation,
// because it is not intended to be user-facing.
def InternalOnly : Documentation {
let Category = DocCatInternalOnly;
}
// Specifies that the attribute is undocumented, but that it _should_ have
// documentation.
def Undocumented : Documentation {
let Category = DocCatUndocumented;
let Content = "No documentation.";
}
include "clang/Basic/AttrDocs.td"
@ -626,7 +641,7 @@ class IgnoredAttr : Attr {
let Ignored = 1;
let ASTNode = 0;
let SemaHandler = 0;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
//
@ -706,14 +721,14 @@ def AlignMac68k : InheritableAttr {
// This attribute has no spellings as it is only ever created implicitly.
let Spellings = [];
let SemaHandler = 0;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def AlignNatural : InheritableAttr {
// This attribute has no spellings as it is only ever created implicitly.
let Spellings = [];
let SemaHandler = 0;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def AlwaysInline : DeclOrStmtAttr {
@ -1188,7 +1203,7 @@ def CUDAInvalidTarget : InheritableAttr {
let Spellings = [];
let Subjects = SubjectList<[Function]>;
let LangOpts = [CUDA];
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def CUDALaunchBounds : InheritableAttr {
@ -1440,7 +1455,9 @@ def Final : InheritableAttr {
let Spellings = [Keyword<"final">, Keyword<"sealed">];
let Accessors = [Accessor<"isSpelledAsSealed", [Keyword<"sealed">]>];
let SemaHandler = 0;
let Documentation = [Undocumented];
// Omitted from docs, since this is language syntax, not an attribute, as far
// as users are concerned.
let Documentation = [InternalOnly];
}
def MinSize : InheritableAttr {
@ -1502,8 +1519,6 @@ def GNUInline : InheritableAttr {
def Hot : InheritableAttr {
let Spellings = [GCC<"hot">];
let Subjects = SubjectList<[Function]>;
// An AST node is created for this attribute, but not actually used beyond
// semantic checking for mutual exclusion with the Cold attribute.
let Documentation = [Undocumented];
let SimpleHandler = 1;
}
@ -1582,7 +1597,7 @@ def MaxFieldAlignment : InheritableAttr {
let Spellings = [];
let Args = [UnsignedArgument<"Alignment">];
let SemaHandler = 0;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def MayAlias : InheritableAttr {
@ -1994,7 +2009,7 @@ def TypeNullUnspecified : TypeAttr {
// qualifier is as an ObjCOwnership attribute with Kind == "none".
def ObjCInertUnsafeUnretained : TypeAttr {
let Spellings = [Keyword<"__unsafe_unretained">];
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def ObjCKindOf : TypeAttr {
@ -2278,7 +2293,9 @@ def Overloadable : Attr {
def Override : InheritableAttr {
let Spellings = [Keyword<"override">];
let SemaHandler = 0;
let Documentation = [Undocumented];
// Omitted from docs, since this is language syntax, not an attribute, as far
// as users are concerned.
let Documentation = [InternalOnly];
}
def Ownership : InheritableAttr {
@ -2467,7 +2484,7 @@ def PragmaClangBSSSection : InheritableAttr {
let Spellings = [];
let Args = [StringArgument<"Name">];
let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def PragmaClangDataSection : InheritableAttr {
@ -2475,7 +2492,7 @@ def PragmaClangDataSection : InheritableAttr {
let Spellings = [];
let Args = [StringArgument<"Name">];
let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def PragmaClangRodataSection : InheritableAttr {
@ -2483,7 +2500,7 @@ def PragmaClangRodataSection : InheritableAttr {
let Spellings = [];
let Args = [StringArgument<"Name">];
let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def PragmaClangRelroSection : InheritableAttr {
@ -2491,7 +2508,7 @@ def PragmaClangRelroSection : InheritableAttr {
let Spellings = [];
let Args = [StringArgument<"Name">];
let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def StrictFP : InheritableAttr {
@ -2499,7 +2516,7 @@ def StrictFP : InheritableAttr {
// Function uses strict floating point operations.
let Spellings = [];
let Subjects = SubjectList<[Function]>;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def PragmaClangTextSection : InheritableAttr {
@ -2507,7 +2524,7 @@ def PragmaClangTextSection : InheritableAttr {
let Spellings = [];
let Args = [StringArgument<"Name">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def Sentinel : InheritableAttr {
@ -3496,7 +3513,7 @@ def DLLExportStaticLocal : InheritableAttr, TargetSpecificAttr<TargetHasDLLImpor
// the function has local static variables, the function is dllexported too.
let Spellings = [];
let Subjects = SubjectList<[Function]>;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def DLLImport : InheritableAttr, TargetSpecificAttr<TargetHasDLLImportExport> {
@ -3522,7 +3539,7 @@ def DLLImportStaticLocal : InheritableAttr, TargetSpecificAttr<TargetHasDLLImpor
// attribute is used to determine whether the variables are imported or not.
let Spellings = [];
let Subjects = SubjectList<[Function]>;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def SelectAny : InheritableAttr {
@ -3588,7 +3605,7 @@ def MSVtorDisp : InheritableAttr {
let AdditionalMembers = [{
MSVtorDispMode getVtorDispMode() const { return MSVtorDispMode(vdm); }
}];
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def InitSeg : Attr {
@ -3680,21 +3697,21 @@ def CapturedRecord : InheritableAttr {
// This attribute has no spellings as it is only ever created implicitly.
let Spellings = [];
let SemaHandler = 0;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def OMPThreadPrivateDecl : InheritableAttr {
// This attribute has no spellings as it is only ever created implicitly.
let Spellings = [];
let SemaHandler = 0;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def OMPCaptureNoInit : InheritableAttr {
// This attribute has no spellings as it is only ever created implicitly.
let Spellings = [];
let SemaHandler = 0;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def OMPCaptureKind : Attr {
@ -3702,7 +3719,7 @@ def OMPCaptureKind : Attr {
let Spellings = [];
let SemaHandler = 0;
let Args = [UnsignedArgument<"CaptureKindVal">];
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
let AdditionalMembers = [{
llvm::omp::Clause getCaptureKind() const {
return static_cast<llvm::omp::Clause>(getCaptureKindVal());
@ -3715,7 +3732,7 @@ def OMPReferencedVar : Attr {
let Spellings = [];
let SemaHandler = 0;
let Args = [ExprArgument<"Ref">];
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def OMPDeclareSimdDecl : Attr {
@ -3788,7 +3805,7 @@ def OMPAllocateDecl : InheritableAttr {
ExprArgument<"Allocator">,
ExprArgument<"Alignment">
];
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def OMPDeclareVariant : InheritableAttr {
@ -3945,7 +3962,7 @@ def Builtin : InheritableAttr {
let Args = [UnsignedArgument<"ID">];
let Subjects = SubjectList<[Function]>;
let SemaHandler = 0;
let Documentation = [Undocumented];
let Documentation = [InternalOnly];
}
def EnforceTCB : InheritableAttr {

View file

@ -4578,7 +4578,8 @@ static void WriteCategoryHeader(const Record *DocCategory,
static std::pair<std::string, SpellingList>
GetAttributeHeadingAndSpellings(const Record &Documentation,
const Record &Attribute) {
const Record &Attribute,
StringRef Cat) {
// FIXME: there is no way to have a per-spelling category for the attribute
// documentation. This may not be a limiting factor since the spellings
// should generally be consistently applied across the category.
@ -4598,7 +4599,7 @@ GetAttributeHeadingAndSpellings(const Record &Documentation,
else {
std::set<std::string> Uniques;
for (auto I = Spellings.begin(), E = Spellings.end();
I != E && Uniques.size() <= 1; ++I) {
I != E; ++I) {
std::string Spelling =
std::string(NormalizeNameForSpellingComparison(I->name()));
Uniques.insert(Spelling);
@ -4607,6 +4608,11 @@ GetAttributeHeadingAndSpellings(const Record &Documentation,
// needs.
if (Uniques.size() == 1)
Heading = *Uniques.begin();
// If it's in the undocumented category, just construct a header by
// concatenating all the spellings. Might not be great, but better than
// nothing.
else if (Cat == "Undocumented")
Heading = llvm::join(Uniques.begin(), Uniques.end(), ", ");
}
}
@ -4701,19 +4707,19 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) {
for (const auto *D : Docs) {
const Record &Doc = *D;
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).
// If the category is "InternalOnly", then there cannot be any other
// documentation categories (otherwise, the attribute would be
// emitted into the docs).
const StringRef Cat = Category->getValueAsString("Name");
bool Undocumented = Cat == "Undocumented";
if (Undocumented && Docs.size() > 1)
bool InternalOnly = Cat == "InternalOnly";
if (InternalOnly && Docs.size() > 1)
PrintFatalError(Doc.getLoc(),
"Attribute is \"Undocumented\", but has multiple "
"Attribute is \"InternalOnly\", but has multiple "
"documentation categories");
if (!Undocumented)
if (!InternalOnly)
SplitDocs[Category].push_back(DocumentationData(
Doc, Attr, GetAttributeHeadingAndSpellings(Doc, Attr)));
Doc, Attr, GetAttributeHeadingAndSpellings(Doc, Attr, Cat)));
}
}