llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Aaron Ballman (AaronBallman) <details> <summary>Changes</summary> Several years ago we began to require all new attributes be documented, but we never had anything enforcing the requirement. However, despite reviewers requesting this documentation, it's been missed often enough that enforcement makes sense in order to reduce maintenance burden. This adds a new tablegen option to spit out the list of undocumented attributes, and a test which lists all of the existing undocumented ones. If a new attribute is added, this test should catch the failure. --- Full diff: https://github.com/llvm/llvm-project/pull/203296.diff 4 Files Affected: - (added) clang/test/AST/undocumented-attrs.cpp (+94) - (modified) clang/utils/TableGen/ClangAttrEmitter.cpp (+44) - (modified) clang/utils/TableGen/TableGen.cpp (+7) - (modified) clang/utils/TableGen/TableGenBackends.h (+2) ``````````diff diff --git a/clang/test/AST/undocumented-attrs.cpp b/clang/test/AST/undocumented-attrs.cpp new file mode 100644 index 0000000000000..c7a2c74631ea2 --- /dev/null +++ b/clang/test/AST/undocumented-attrs.cpp @@ -0,0 +1,94 @@ +// RUN: clang-tblgen -gen-clang-attr-undocumented-list -I%S/../../include/ %S/../../include/clang/Basic/Attr.td -o - | FileCheck %s + +This test serves to prevent us adding new attributes to Clang that are +undocumented. All new attributes should be documented. + +The list of attributes below should NEVER grow. It should gradually shrink to 0. + +CHECK-LABEL: Undocumented attributes: +CHECK-NEXT: AcquiredAfter +CHECK-NEXT: AcquiredBefore +CHECK-NEXT: Alias +CHECK-NEXT: Aligned +CHECK-NEXT: AnalyzerNoReturn +CHECK-NEXT: Annotate +CHECK-NEXT: ArcWeakrefUnavailable +CHECK-NEXT: AvailableOnlyInDefaultEvalMethod +CHECK-NEXT: Blocks +CHECK-NEXT: CDecl +CHECK-NEXT: CFAuditedTransfer +CHECK-NEXT: CFUnknownTransfer +CHECK-NEXT: CUDAConstant +CHECK-NEXT: CUDADevice +CHECK-NEXT: CUDAGlobal +CHECK-NEXT: CUDAHost +CHECK-NEXT: CUDALaunchBounds +CHECK-NEXT: CUDAShared +CHECK-NEXT: Capability +CHECK-NEXT: Common +CHECK-NEXT: Const +CHECK-NEXT: ConsumableAutoCast +CHECK-NEXT: ConsumableSetOnRead +CHECK-NEXT: FormatArg +CHECK-NEXT: GuardedBy +CHECK-NEXT: GuardedVar +CHECK-NEXT: IBAction +CHECK-NEXT: IBOutlet +CHECK-NEXT: IBOutletCollection +CHECK-NEXT: IntelOclBicc +CHECK-NEXT: LockReturned +CHECK-NEXT: Lockable +CHECK-NEXT: LocksExcluded +CHECK-NEXT: M68kInterrupt +CHECK-NEXT: MSP430Interrupt +CHECK-NEXT: MatrixType +CHECK-NEXT: MayAlias +CHECK-NEXT: Mips16 +CHECK-NEXT: Mode +CHECK-NEXT: Naked +CHECK-NEXT: NeonPolyVectorType +CHECK-NEXT: NeonVectorType +CHECK-NEXT: NoCommon +CHECK-NEXT: NoFieldProtection +CHECK-NEXT: NoInstrumentFunction +CHECK-NEXT: NoMips16 +CHECK-NEXT: NoReturn +CHECK-NEXT: NoThreadSafetyAnalysis +CHECK-NEXT: ObjCBridge +CHECK-NEXT: ObjCBridgeMutable +CHECK-NEXT: ObjCBridgeRelated +CHECK-NEXT: ObjCDesignatedInitializer +CHECK-NEXT: ObjCException +CHECK-NEXT: ObjCExplicitProtocolImpl +CHECK-NEXT: ObjCGC +CHECK-NEXT: ObjCIndependentClass +CHECK-NEXT: ObjCKindOf +CHECK-NEXT: ObjCNSObject +CHECK-NEXT: ObjCOwnership +CHECK-NEXT: ObjCPreciseLifetime +CHECK-NEXT: ObjCRequiresPropertyDefs +CHECK-NEXT: ObjCReturnsInnerPointer +CHECK-NEXT: ObjCRootClass +CHECK-NEXT: OverflowBehavior +CHECK-NEXT: Packed +CHECK-NEXT: Pascal +CHECK-NEXT: PointerFieldProtection +CHECK-NEXT: PtGuardedBy +CHECK-NEXT: PtGuardedVar +CHECK-NEXT: Pure +CHECK-NEXT: ReentrantCapability +CHECK-NEXT: ReqdWorkGroupSize +CHECK-NEXT: RequiresCapability +CHECK-NEXT: ReturnsTwice +CHECK-NEXT: ScopedLockable +CHECK-NEXT: Unavailable +CHECK-NEXT: Uuid +CHECK-NEXT: VTablePointerAuthentication +CHECK-NEXT: VecReturn +CHECK-NEXT: VecTypeHint +CHECK-NEXT: VectorSize +CHECK-NEXT: Visibility +CHECK-NEXT: WeakImport +CHECK-NEXT: WeakRef +CHECK-NEXT: WorkGroupSizeHint +CHECK-NEXT: Total: 85 diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 1eaec5f07c75e..b230bfa7e3f01 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -5568,6 +5568,50 @@ static void WriteDocumentation(const RecordKeeper &Records, OS << "\n\n\n"; } +void GetListOfUndocumentedAttributes( + const RecordKeeper &Records, + std::vector<const Record *> &UndocumentedAttrs) { + const Record *Documentation = Records.getDef("GlobalDocumentation"); + if (!Documentation) { + PrintFatalError("The Documentation top-level definition is missing."); + return; + } + + for (const auto *A : Records.getAllDerivedDefinitions("Attr")) { + const Record &Attr = *A; + std::vector<const Record *> Docs = + Attr.getValueAsListOfDefs("Documentation"); + for (const auto *D : Docs) { + const Record &Doc = *D; + const Record *Category = Doc.getValueAsDef("Category"); + if (Category->getValueAsString("Name") == "Undocumented") + UndocumentedAttrs.push_back(A); + } + } +} + +void EmitClangUndocumentedAttrlist(const llvm::RecordKeeper &Records, + llvm::raw_ostream &OS) { + // Emit a newline separated list of attributes whose Documentation is set to + // Undocumented. + std::vector<const Record *> UndocumentedAttrs; + GetListOfUndocumentedAttributes(Records, UndocumentedAttrs); + + // Print a small header; this helps catch the situation where someone adds an + // attribute without documentation but it is alphabetically before the first + // attribute in the test file. + OS << "Undocumented attributes:\n"; + + for (const auto* A : UndocumentedAttrs) { + OS << A->getName() << "\n"; + } + + // Also print the count; this helps catch attributes after the last one in + // the test file. + OS << "Total: " << UndocumentedAttrs.size() << "\n"; +} + + void EmitClangAttrDocs(const RecordKeeper &Records, raw_ostream &OS) { // Get the documentation introduction paragraph. const Record *Documentation = Records.getDef("GlobalDocumentation"); diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp index 0ce9d8306ae16..9e1a55dcbc63b 100644 --- a/clang/utils/TableGen/TableGen.cpp +++ b/clang/utils/TableGen/TableGen.cpp @@ -46,6 +46,7 @@ enum ActionType { GenClangAttrIsTypeDependent, GenClangAttrTextNodeDump, GenClangAttrNodeTraverse, + GenClangAttrUndocumentedAttrList, GenClangBasicReader, GenClangBasicWriter, GenClangBuiltins, @@ -191,6 +192,9 @@ cl::opt<ActionType> Action( "Generate clang attribute text node dumper"), clEnumValN(GenClangAttrNodeTraverse, "gen-clang-attr-node-traverse", "Generate clang attribute traverser"), + clEnumValN(GenClangAttrUndocumentedAttrList, + "gen-clang-attr-undocumented-list", + "Generate a list of undocumented attributes"), clEnumValN(GenClangBuiltins, "gen-clang-builtins", "Generate clang builtins list"), clEnumValN(GenClangBuiltinTemplates, "gen-clang-builtin-templates", @@ -450,6 +454,9 @@ bool ClangTableGenMain(raw_ostream &OS, const RecordKeeper &Records) { case GenClangAttrNodeTraverse: EmitClangAttrNodeTraverse(Records, OS); break; + case GenClangAttrUndocumentedAttrList: + EmitClangUndocumentedAttrlist(Records, OS); + break; case GenClangBuiltins: EmitClangBuiltins(Records, OS); break; diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h index f9bd7ccf9d0d8..15d8b9894398f 100644 --- a/clang/utils/TableGen/TableGenBackends.h +++ b/clang/utils/TableGen/TableGenBackends.h @@ -88,6 +88,8 @@ void EmitClangAttrTextNodeDump(const llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitClangAttrNodeTraverse(const llvm::RecordKeeper &Records, llvm::raw_ostream &OS); +void EmitClangUndocumentedAttrlist(const llvm::RecordKeeper &Records, + llvm::raw_ostream &OS); void EmitClangAttrDocTable(const llvm::RecordKeeper &Records, llvm::raw_ostream &OS); `````````` </details> https://github.com/llvm/llvm-project/pull/203296 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
