Skip to content

Commit 03721ac

Browse files
add @_documentation(...) attribute to influence SymbolGraphGen
rdar://79049241
1 parent baeb988 commit 03721ac

24 files changed

+435
-10
lines changed

docs/ReferenceGuides/UnderscoredAttributes.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,27 @@ extension Text {
121121
}
122122
```
123123

124+
## `@_documentation(metadata: ...)`
125+
126+
Adds "documentation metadata" to the symbol. The identifier in the attribute is
127+
added to the symbol graph in the `"metadata"` field of the symbol. This can be
128+
used to add an arbitrary grouping or other indicator to symbols for use in
129+
documentation.
130+
131+
## `@_documentation(visibility: ...)`
132+
133+
Forces the symbol to be treated as the given access level when checking
134+
visibility. This can be used to, for example, force a symbol with an underscored
135+
name to appear in `public` symbol graphs, or treat an otherwise-`public` symbol
136+
as being `internal` or `private` for the purposes of documentation, to hide it
137+
from `public` docs.
138+
139+
This can also be applied to `@_exported import` statements to only include the
140+
imported symbols in symbol graphs with the given minimum access level. For
141+
example, applying `@_documentation(visibility: internal)` to an `@_exported
142+
import` statement will hide the imported symbols from `public` symbol graphs and
143+
documentation, but show them on `internal` symbol graphs and documentation.
144+
124145
## `@_dynamicReplacement(for: targetFunc(label:))`
125146

126147
Marks a function as the dynamic replacement for another `dynamic` function.

include/swift/AST/Attr.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,11 @@ SIMPLE_DECL_ATTR(_alwaysEmitConformanceMetadata, AlwaysEmitConformanceMetadata,
746746
OnProtocol | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
747747
132)
748748

749+
DECL_ATTR(_documentation, Documentation,
750+
OnAnyDecl | UserInaccessible |
751+
APIBreakingToAdd | APIStableToRemove | ABIStableToAdd | ABIStableToRemove,
752+
133)
753+
749754
// If you're adding a new underscored attribute here, please document it in
750755
// docs/ReferenceGuides/UnderscoredAttributes.md.
751756

include/swift/AST/Attr.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2226,6 +2226,28 @@ class BackDeployAttr: public DeclAttribute {
22262226
}
22272227
};
22282228

2229+
/// The `@_documentation(...)` attribute, used to note a "category" for a
2230+
/// symbol to be associated with, with special cases for forcing a symbol to be
2231+
/// hidden or visible.
2232+
class DocumentationAttr: public DeclAttribute {
2233+
public:
2234+
DocumentationAttr(SourceLoc AtLoc, SourceRange Range,
2235+
StringRef Metadata, Optional<AccessLevel> Visibility,
2236+
bool Implicit)
2237+
: DeclAttribute(DAK_Documentation, AtLoc, Range, Implicit),
2238+
Metadata(Metadata), Visibility(Visibility) {}
2239+
2240+
DocumentationAttr(StringRef Metadata, Optional<AccessLevel> Visibility, bool Implicit)
2241+
: DocumentationAttr(SourceLoc(), SourceRange(), Metadata, Visibility, Implicit) {}
2242+
2243+
const StringRef Metadata;
2244+
const Optional<AccessLevel> Visibility;
2245+
2246+
static bool classof(const DeclAttribute *DA) {
2247+
return DA->getKind() == DAK_Documentation;
2248+
}
2249+
};
2250+
22292251

22302252
/// Attributes that may be applied to declarations.
22312253
class DeclAttributes {

include/swift/AST/DiagnosticsParse.def

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,6 +1762,27 @@ WARNING(warn_attr_unsafe_removed,none,
17621762
"'%0' attribute has been removed in favor of @preconcurrency",
17631763
(StringRef))
17641764

1765+
// _documentation
1766+
ERROR(documentation_attr_expected_argument,none,
1767+
"@_documentation attribute expected 'visibility' or 'metadata' argument",
1768+
())
1769+
ERROR(documentation_attr_unknown_argument,none,
1770+
"unknown argument '%0', expected 'visibility' or 'metadata'",
1771+
(StringRef))
1772+
ERROR(documentation_attr_expected_access_level,none,
1773+
"@_documentation attribute's 'visibility' argument expected an access level",
1774+
())
1775+
ERROR(documentation_attr_unknown_access_level,none,
1776+
"unknown visibility '%0', expected an access level keyword",
1777+
(StringRef))
1778+
ERROR(documentation_attr_duplicate_visibility,none,
1779+
"cannot give more than one visibility to the same item", ())
1780+
ERROR(documentation_attr_metadata_expected_identifier,none,
1781+
"@_documentation attribute's 'metadata' argument expected a plain identifier",
1782+
())
1783+
ERROR(documentation_attr_duplicate_metadata,none,
1784+
"cannot give more than one metadata argument to the same item", ())
1785+
17651786
//------------------------------------------------------------------------------
17661787
// MARK: Generics parsing diagnostics
17671788
//------------------------------------------------------------------------------

include/swift/AST/Import.h

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#ifndef SWIFT_IMPORT_H
2020
#define SWIFT_IMPORT_H
2121

22+
#include "swift/AST/AttrKind.h"
2223
#include "swift/AST/Identifier.h"
2324
#include "swift/Basic/Located.h"
2425
#include "swift/Basic/OptionSet.h"
@@ -575,13 +576,18 @@ struct AttributedImport {
575576
/// is the source range covering the annotation.
576577
SourceRange preconcurrencyRange;
577578

579+
/// If the import declaration has a `@_documentation(visibility: <access>)`
580+
/// attribute, this is the given access level.
581+
Optional<AccessLevel> docVisibility;
582+
578583
AttributedImport(ModuleInfo module, SourceLoc importLoc = SourceLoc(),
579584
ImportOptions options = ImportOptions(),
580585
StringRef filename = {}, ArrayRef<Identifier> spiGroups = {},
581-
SourceRange preconcurrencyRange = {})
586+
SourceRange preconcurrencyRange = {},
587+
Optional<AccessLevel> docVisibility = None)
582588
: module(module), importLoc(importLoc), options(options),
583589
sourceFileArg(filename), spiGroups(spiGroups),
584-
preconcurrencyRange(preconcurrencyRange) {
590+
preconcurrencyRange(preconcurrencyRange), docVisibility(docVisibility) {
585591
assert(!(options.contains(ImportFlags::Exported) &&
586592
options.contains(ImportFlags::ImplementationOnly)) ||
587593
options.contains(ImportFlags::Reserved));
@@ -591,14 +597,15 @@ struct AttributedImport {
591597
AttributedImport(ModuleInfo module, AttributedImport<OtherModuleInfo> other)
592598
: AttributedImport(module, other.importLoc, other.options,
593599
other.sourceFileArg, other.spiGroups,
594-
other.preconcurrencyRange) { }
600+
other.preconcurrencyRange, other.docVisibility) { }
595601

596602
friend bool operator==(const AttributedImport<ModuleInfo> &lhs,
597603
const AttributedImport<ModuleInfo> &rhs) {
598604
return lhs.module == rhs.module &&
599605
lhs.options.toRaw() == rhs.options.toRaw() &&
600606
lhs.sourceFileArg == rhs.sourceFileArg &&
601-
lhs.spiGroups == rhs.spiGroups;
607+
lhs.spiGroups == rhs.spiGroups &&
608+
lhs.docVisibility == rhs.docVisibility;
602609
}
603610

604611
AttributedImport<ImportedModule> getLoaded(ModuleDecl *loadedModule) const {
@@ -750,14 +757,14 @@ struct DenseMapInfo<swift::AttributedImport<ModuleInfo>> {
750757
SourceLocDMI::getEmptyKey(),
751758
ImportOptionsDMI::getEmptyKey(),
752759
StringRefDMI::getEmptyKey(),
753-
{});
760+
{}, {}, None);
754761
}
755762
static inline AttributedImport getTombstoneKey() {
756763
return AttributedImport(ModuleInfoDMI::getTombstoneKey(),
757764
SourceLocDMI::getEmptyKey(),
758765
ImportOptionsDMI::getTombstoneKey(),
759766
StringRefDMI::getTombstoneKey(),
760-
{});
767+
{}, {}, None);
761768
}
762769
static inline unsigned getHashValue(const AttributedImport &import) {
763770
return detail::combineHashValue(
@@ -771,7 +778,8 @@ struct DenseMapInfo<swift::AttributedImport<ModuleInfo>> {
771778
return ModuleInfoDMI::isEqual(a.module, b.module) &&
772779
ImportOptionsDMI::isEqual(a.options, b.options) &&
773780
StringRefDMI::isEqual(a.sourceFileArg, b.sourceFileArg) &&
774-
a.spiGroups == b.spiGroups;
781+
a.spiGroups == b.spiGroups &&
782+
a.docVisibility == b.docVisibility;
775783
}
776784
};
777785
}

include/swift/AST/Module.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -953,7 +953,8 @@ inline SourceLoc extractNearestSourceLoc(const ModuleDecl *mod) {
953953
/// Collects modules that this module imports via `@_exported import`.
954954
void collectParsedExportedImports(const ModuleDecl *M,
955955
SmallPtrSetImpl<ModuleDecl *> &Imports,
956-
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> &QualifiedImports);
956+
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> &QualifiedImports,
957+
llvm::function_ref<bool(AttributedImport<ImportedModule>)> includeImport = nullptr);
957958

958959
} // end namespace swift
959960

include/swift/Parse/Parser.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,14 @@ class Parser {
11451145
bool parseBackDeployAttribute(DeclAttributes &Attributes, StringRef AttrName,
11461146
SourceLoc AtLoc, SourceLoc Loc);
11471147

1148+
/// Parse the @_documentation attribute.
1149+
ParserResult<DocumentationAttr> parseDocumentationAttribute(SourceLoc AtLoc,
1150+
SourceLoc Loc);
1151+
1152+
/// Parse a single argument from a @_documentation attribute.
1153+
bool parseDocumentationAttributeArgument(Optional<StringRef> &Metadata,
1154+
Optional<AccessLevel> &Visibility);
1155+
11481156
/// Parse a specific attribute.
11491157
ParserStatus parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
11501158
PatternBindingInitializer *&initContext,
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//===--- DocumentationCategory.h - Accessors for @_documentation ----------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_SYMBOLGRAPHGEN_DOCUMENTATIONCATEGORY_H
14+
#define SWIFT_SYMBOLGRAPHGEN_DOCUMENTATIONCATEGORY_H
15+
16+
#include "swift/AST/Decl.h"
17+
18+
#include "llvm/Support/Compiler.h"
19+
20+
namespace swift {
21+
namespace symbolgraphgen {
22+
23+
LLVM_ATTRIBUTE_USED
24+
static StringRef documentationMetadataForDecl(const Decl *D) {
25+
if (!D) return {};
26+
27+
if (const auto *DC = D->getAttrs().getAttribute<DocumentationAttr>()) {
28+
return DC->Metadata;
29+
}
30+
31+
return {};
32+
}
33+
34+
LLVM_ATTRIBUTE_USED
35+
static Optional<AccessLevel> documentationVisibilityForDecl(const Decl *D) {
36+
if (!D) return None;
37+
38+
if (const auto *DC = D->getAttrs().getAttribute<DocumentationAttr>()) {
39+
return DC->Visibility;
40+
}
41+
42+
return None;
43+
}
44+
45+
} // namespace symbolgraphgen
46+
} // namespace swift
47+
48+
#endif // SWIFT_SYMBOLGRAPHGEN_DOCUMENTATIONCATEGORY_H

lib/AST/Attr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,8 @@ StringRef DeclAttribute::getAttrName() const {
14401440
return "_unavailableFromAsync";
14411441
case DAK_BackDeploy:
14421442
return "_backDeploy";
1443+
case DAK_Documentation:
1444+
return "_documentation";
14431445
}
14441446
llvm_unreachable("bad DeclAttrKind");
14451447
}

lib/AST/Module.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -794,12 +794,14 @@ bool ModuleDecl::shouldCollectDisplayDecls() const {
794794

795795
void swift::collectParsedExportedImports(const ModuleDecl *M,
796796
SmallPtrSetImpl<ModuleDecl *> &Imports,
797-
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> &QualifiedImports) {
797+
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> &QualifiedImports,
798+
llvm::function_ref<bool(AttributedImport<ImportedModule>)> includeImport) {
798799
for (const FileUnit *file : M->getFiles()) {
799800
if (const SourceFile *source = dyn_cast<SourceFile>(file)) {
800801
if (source->hasImports()) {
801802
for (auto import : source->getImports()) {
802803
if (import.options.contains(ImportFlags::Exported) &&
804+
(!includeImport || includeImport(import)) &&
803805
import.module.importedModule->shouldCollectDisplayDecls()) {
804806
auto *TheModule = import.module.importedModule;
805807

0 commit comments

Comments
 (0)