Skip to content

introduce a @_documentation(...) attribute to influence SymbolGraphGen #60242

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/ReferenceGuides/UnderscoredAttributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,27 @@ extension Text {
}
```

## `@_documentation(metadata: ...)`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume the value of the metadata parameter is just a string that be specified with or without quotes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now it can only be an identifier, but i could see about making it a quoted string as well.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's a string in quotes, developers could stick in useful metadata like JSON, CSV, or hex encoded images which would be fun 👌🏼


Adds "documentation metadata" to the symbol. The identifier in the attribute is
added to the symbol graph in the `"metadata"` field of the symbol. This can be
used to add an arbitrary grouping or other indicator to symbols for use in
documentation.
Copy link
Contributor

@franklinsch franklinsch Aug 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you able to specify multiple @_documentation(metadata: …) attributes for the same declaration?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure; i'll have to check. Offhand, i think the answer is "no" because of checks for duplicate attributes, but i'm not confident about it.


## `@_documentation(visibility: ...)`

Forces the symbol to be treated as the given access level when checking
visibility. This can be used to, for example, force a symbol with an underscored
name to appear in `public` symbol graphs, or treat an otherwise-`public` symbol
as being `internal` or `private` for the purposes of documentation, to hide it
from `public` docs.

This can also be applied to `@_exported import` statements to only include the
imported symbols in symbol graphs with the given minimum access level. For
example, applying `@_documentation(visibility: internal)` to an `@_exported
import` statement will hide the imported symbols from `public` symbol graphs and
documentation, but show them on `internal` symbol graphs and documentation.

## `@_dynamicReplacement(for: targetFunc(label:))`

Marks a function as the dynamic replacement for another `dynamic` function.
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,11 @@ SIMPLE_DECL_ATTR(_spiOnly, SPIOnly,
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
135)

DECL_ATTR(_documentation, Documentation,
OnAnyDecl | UserInaccessible |
APIBreakingToAdd | APIStableToRemove | ABIStableToAdd | ABIStableToRemove,
136)

// If you're adding a new underscored attribute here, please document it in
// docs/ReferenceGuides/UnderscoredAttributes.md.

Expand Down
21 changes: 21 additions & 0 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2244,6 +2244,27 @@ class ExposeAttr : public DeclAttribute {
}
};

/// The `@_documentation(...)` attribute, used to override a symbol's visibility
/// in symbol graphs, and/or adding arbitrary metadata to it.
class DocumentationAttr: public DeclAttribute {
public:
DocumentationAttr(SourceLoc AtLoc, SourceRange Range,
StringRef Metadata, Optional<AccessLevel> Visibility,
bool Implicit)
: DeclAttribute(DAK_Documentation, AtLoc, Range, Implicit),
Metadata(Metadata), Visibility(Visibility) {}

DocumentationAttr(StringRef Metadata, Optional<AccessLevel> Visibility, bool Implicit)
: DocumentationAttr(SourceLoc(), SourceRange(), Metadata, Visibility, Implicit) {}

const StringRef Metadata;
const Optional<AccessLevel> Visibility;

static bool classof(const DeclAttribute *DA) {
return DA->getKind() == DAK_Documentation;
}
};

/// Attributes that may be applied to declarations.
class DeclAttributes {
/// Linked list of declaration attributes.
Expand Down
22 changes: 22 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1763,6 +1763,28 @@ WARNING(warn_attr_unsafe_removed,none,
"'%0' attribute has been removed in favor of @preconcurrency",
(StringRef))

// _documentation
ERROR(documentation_attr_expected_argument,none,
"@_documentation attribute expected 'visibility' or 'metadata' argument",
())
ERROR(documentation_attr_unknown_argument,none,
"unknown argument '%0', expected 'visibility' or 'metadata'",
(StringRef))
ERROR(documentation_attr_expected_access_level,none,
"@_documentation attribute's 'visibility' argument expected an access level",
())
ERROR(documentation_attr_unknown_access_level,none,
"unknown visibility '%0', expected an access level keyword",
(StringRef))
ERROR(documentation_attr_duplicate_visibility,none,
"cannot give more than one visibility to the same item", ())
ERROR(documentation_attr_metadata_expected_text,none,
"@_documentation attribute's 'metadata' argument expected an identifier or "
"quoted string",
())
ERROR(documentation_attr_duplicate_metadata,none,
"cannot give more than one metadata argument to the same item", ())

//------------------------------------------------------------------------------
// MARK: Generics parsing diagnostics
//------------------------------------------------------------------------------
Expand Down
22 changes: 15 additions & 7 deletions include/swift/AST/Import.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#ifndef SWIFT_IMPORT_H
#define SWIFT_IMPORT_H

#include "swift/AST/AttrKind.h"
#include "swift/AST/Identifier.h"
#include "swift/Basic/Located.h"
#include "swift/Basic/OptionSet.h"
Expand Down Expand Up @@ -579,13 +580,18 @@ struct AttributedImport {
/// is the source range covering the annotation.
SourceRange preconcurrencyRange;

/// If the import declaration has a `@_documentation(visibility: <access>)`
/// attribute, this is the given access level.
Optional<AccessLevel> docVisibility;

AttributedImport(ModuleInfo module, SourceLoc importLoc = SourceLoc(),
ImportOptions options = ImportOptions(),
StringRef filename = {}, ArrayRef<Identifier> spiGroups = {},
SourceRange preconcurrencyRange = {})
SourceRange preconcurrencyRange = {},
Optional<AccessLevel> docVisibility = None)
: module(module), importLoc(importLoc), options(options),
sourceFileArg(filename), spiGroups(spiGroups),
preconcurrencyRange(preconcurrencyRange) {
preconcurrencyRange(preconcurrencyRange), docVisibility(docVisibility) {
assert(!(options.contains(ImportFlags::Exported) &&
options.contains(ImportFlags::ImplementationOnly)) ||
options.contains(ImportFlags::Reserved));
Expand All @@ -595,14 +601,15 @@ struct AttributedImport {
AttributedImport(ModuleInfo module, AttributedImport<OtherModuleInfo> other)
: AttributedImport(module, other.importLoc, other.options,
other.sourceFileArg, other.spiGroups,
other.preconcurrencyRange) { }
other.preconcurrencyRange, other.docVisibility) { }

friend bool operator==(const AttributedImport<ModuleInfo> &lhs,
const AttributedImport<ModuleInfo> &rhs) {
return lhs.module == rhs.module &&
lhs.options.toRaw() == rhs.options.toRaw() &&
lhs.sourceFileArg == rhs.sourceFileArg &&
lhs.spiGroups == rhs.spiGroups;
lhs.spiGroups == rhs.spiGroups &&
lhs.docVisibility == rhs.docVisibility;
}

AttributedImport<ImportedModule> getLoaded(ModuleDecl *loadedModule) const {
Expand Down Expand Up @@ -754,14 +761,14 @@ struct DenseMapInfo<swift::AttributedImport<ModuleInfo>> {
SourceLocDMI::getEmptyKey(),
ImportOptionsDMI::getEmptyKey(),
StringRefDMI::getEmptyKey(),
{});
{}, {}, None);
}
static inline AttributedImport getTombstoneKey() {
return AttributedImport(ModuleInfoDMI::getTombstoneKey(),
SourceLocDMI::getEmptyKey(),
ImportOptionsDMI::getTombstoneKey(),
StringRefDMI::getTombstoneKey(),
{});
{}, {}, None);
}
static inline unsigned getHashValue(const AttributedImport &import) {
return detail::combineHashValue(
Expand All @@ -775,7 +782,8 @@ struct DenseMapInfo<swift::AttributedImport<ModuleInfo>> {
return ModuleInfoDMI::isEqual(a.module, b.module) &&
ImportOptionsDMI::isEqual(a.options, b.options) &&
StringRefDMI::isEqual(a.sourceFileArg, b.sourceFileArg) &&
a.spiGroups == b.spiGroups;
a.spiGroups == b.spiGroups &&
a.docVisibility == b.docVisibility;
}
};
}
Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,8 @@ inline SourceLoc extractNearestSourceLoc(const ModuleDecl *mod) {
/// Collects modules that this module imports via `@_exported import`.
void collectParsedExportedImports(const ModuleDecl *M,
SmallPtrSetImpl<ModuleDecl *> &Imports,
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> &QualifiedImports);
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> &QualifiedImports,
llvm::function_ref<bool(AttributedImport<ImportedModule>)> includeImport = nullptr);

} // end namespace swift

Expand Down
8 changes: 8 additions & 0 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,14 @@ class Parser {
bool parseBackDeployAttribute(DeclAttributes &Attributes, StringRef AttrName,
SourceLoc AtLoc, SourceLoc Loc);

/// Parse the @_documentation attribute.
ParserResult<DocumentationAttr> parseDocumentationAttribute(SourceLoc AtLoc,
SourceLoc Loc);

/// Parse a single argument from a @_documentation attribute.
bool parseDocumentationAttributeArgument(Optional<StringRef> &Metadata,
Optional<AccessLevel> &Visibility);

/// Parse a specific attribute.
ParserStatus parseDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
PatternBindingInitializer *&initContext,
Expand Down
48 changes: 48 additions & 0 deletions include/swift/SymbolGraphGen/DocumentationCategory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//===--- DocumentationCategory.h - Accessors for @_documentation ----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_SYMBOLGRAPHGEN_DOCUMENTATIONCATEGORY_H
#define SWIFT_SYMBOLGRAPHGEN_DOCUMENTATIONCATEGORY_H

#include "swift/AST/Decl.h"

#include "llvm/Support/Compiler.h"

namespace swift {
namespace symbolgraphgen {

LLVM_ATTRIBUTE_USED
static StringRef documentationMetadataForDecl(const Decl *D) {
if (!D) return {};

if (const auto *DC = D->getAttrs().getAttribute<DocumentationAttr>()) {
return DC->Metadata;
}

return {};
}

LLVM_ATTRIBUTE_USED
static Optional<AccessLevel> documentationVisibilityForDecl(const Decl *D) {
if (!D) return None;

if (const auto *DC = D->getAttrs().getAttribute<DocumentationAttr>()) {
return DC->Visibility;
}

return None;
}

} // namespace symbolgraphgen
} // namespace swift

#endif // SWIFT_SYMBOLGRAPHGEN_DOCUMENTATIONCATEGORY_H
2 changes: 2 additions & 0 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1450,6 +1450,8 @@ StringRef DeclAttribute::getAttrName() const {
return "_backDeploy";
case DAK_Expose:
return "_expose";
case DAK_Documentation:
return "_documentation";
}
llvm_unreachable("bad DeclAttrKind");
}
Expand Down
4 changes: 3 additions & 1 deletion lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,12 +794,14 @@ bool ModuleDecl::shouldCollectDisplayDecls() const {

void swift::collectParsedExportedImports(const ModuleDecl *M,
SmallPtrSetImpl<ModuleDecl *> &Imports,
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> &QualifiedImports) {
llvm::SmallDenseMap<ModuleDecl *, SmallPtrSet<Decl *, 4>, 4> &QualifiedImports,
llvm::function_ref<bool(AttributedImport<ImportedModule>)> includeImport) {
for (const FileUnit *file : M->getFiles()) {
if (const SourceFile *source = dyn_cast<SourceFile>(file)) {
if (source->hasImports()) {
for (auto import : source->getImports()) {
if (import.options.contains(ImportFlags::Exported) &&
(!includeImport || includeImport(import)) &&
import.module.importedModule->shouldCollectDisplayDecls()) {
auto *TheModule = import.module.importedModule;

Expand Down
Loading