Improve the "Diagnostic items" chapter (#1427)

This commit is contained in:
Tshepang Mbambo 2022-08-13 03:00:38 +02:00 committed by GitHub
parent 452b5abdd6
commit d3daa1f28e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 48 additions and 29 deletions

View File

@ -1,4 +1,5 @@
# Diagnostic Items # Diagnostic Items
While writing lints it's common to check for specific types, traits and While writing lints it's common to check for specific types, traits and
functions. This raises the question on how to check for these. Types can be functions. This raises the question on how to check for these. Types can be
checked by their complete type path. However, this requires hard coding paths checked by their complete type path. However, this requires hard coding paths
@ -7,7 +8,8 @@ rustc has introduced diagnostic items that are used to identify types via
[`Symbol`]s. [`Symbol`]s.
## Finding diagnostic items ## Finding diagnostic items
Diagnostic items are added to items inside `rustc`/`std`/`core` with the
Diagnostic items are added to items inside `rustc`/`std`/`core`/`alloc` with the
`rustc_diagnostic_item` attribute. The item for a specific type can be found by `rustc_diagnostic_item` attribute. The item for a specific type can be found by
opening the source code in the documentation and looking for this attribute. opening the source code in the documentation and looking for this attribute.
Note that it's often added with the `cfg_attr` attribute to avoid compilation Note that it's often added with the `cfg_attr` attribute to avoid compilation
@ -19,12 +21,15 @@ errors during tests. A definition often looks like this:
struct Penguin; struct Penguin;
``` ```
Diagnostic items are usually only added to traits, types and standalone Diagnostic items are usually only added to traits,
functions. If the goal is to check for an associated type or method, please use types,
the diagnostic item of the item and reference [*How To Use Diagnostic and standalone functions.
Items*](#how-to-use-diagnostic-items). If the goal is to check for an associated type or method,
please use the diagnostic item of the item and reference
[*Using Diagnostic Items*](#using-diagnostic-items).
## Adding diagnostic items ## Adding diagnostic items
A new diagnostic item can be added with these two steps: A new diagnostic item can be added with these two steps:
1. Find the target item inside the Rust repo. Now add the diagnostic item as a 1. Find the target item inside the Rust repo. Now add the diagnostic item as a
@ -43,45 +48,55 @@ A new diagnostic item can be added with these two steps:
For the naming conventions of diagnostic items, please refer to For the naming conventions of diagnostic items, please refer to
[*Naming Conventions*](#naming-conventions). [*Naming Conventions*](#naming-conventions).
2. As of <!-- date-check --> February 2022, diagnostic items in code are 2. <!-- date-check: Aug 2022 -->
accessed via symbols in [`rustc_span::symbol::sym`]. To add your newly Diagnostic items in code are accessed via symbols in
created diagnostic item simply open the module file and add the name (In [`rustc_span::symbol::sym`].
this case `Cat`) at the correct point in the list. To add your newly-created diagnostic item,
simply open the module file,
and add the name (In this case `Cat`) at the correct point in the list.
Now you can create a pull request with your changes. :tada: (Note that when Now you can create a pull request with your changes. :tada:
using diagnostic items in other projects like Clippy, it might take some time
until the repos get synchronized.) > NOTE:
> When using diagnostic items in other projects like Clippy,
> it might take some time until the repos get synchronized.
## Naming conventions ## Naming conventions
Diagnostic items don't have a set in stone naming convention yet. These are
some guidelines that should be used for the future, but might differ from
existing names:
* Types, traits and enums are named using UpperCamelCase (Examples: `Iterator`, Diagnostic items don't have a naming convention yet.
* `HashMap`, ...) Following are some guidelines that should be used in future,
* For type names that are used multiple times like `Writer` it's good to choose but might differ from existing names:
a more precise name, maybe by adding the module to it. (Example: `IoWriter`)
* Associated items should not get their own diagnostic items, but instead be * Types, traits, and enums are named using UpperCamelCase
accessed indirectly by the diagnostic item of the type they're originating (Examples: `Iterator` and `HashMap`)
from. * For type names that are used multiple times,
like `Writer`,
it's good to choose a more precise name,
maybe by adding the module to it
(Example: `IoWriter`)
* Associated items should not get their own diagnostic items,
but instead be accessed indirectly by the diagnostic item
of the type they're originating from.
* Freestanding functions like `std::mem::swap()` should be named using * Freestanding functions like `std::mem::swap()` should be named using
`snake_case` with one important (export) module as a prefix (Example: `snake_case` with one important (export) module as a prefix
`mem_swap`, `cmp_max`) (Examples: `mem_swap` and `cmp_max`)
* Modules should usually not have a diagnostic item attached to them. * Modules should usually not have a diagnostic item attached to them.
Diagnostic items were added to avoid the usage of paths, using them on Diagnostic items were added to avoid the usage of paths,
modules would therefore most likely to be counterproductive. and using them on modules would therefore most likely be counterproductive.
## Using diagnostic items ## Using diagnostic items
In rustc, diagnostic items are looked up via [`Symbol`]s from inside the In rustc, diagnostic items are looked up via [`Symbol`]s from inside the
[`rustc_span::symbol::sym`] module. These can then be mapped to [`DefId`]s [`rustc_span::symbol::sym`] module. These can then be mapped to [`DefId`]s
using [`TyCtxt::get_diagnostic_item()`] or checked if they match a [`DefId`] using [`TyCtxt::get_diagnostic_item()`] or checked if they match a [`DefId`]
using [`TyCtxt::is_diagnostic_item()`]. When mapping from a diagnostic item to using [`TyCtxt::is_diagnostic_item()`]. When mapping from a diagnostic item to
a [`DefId`], the method will return a `Option<DefId>`. This can be `None` if a [`DefId`], the method will return a `Option<DefId>`. This can be `None` if
either the symbol isn't a diagnostic item or the type is not registered, for either the symbol isn't a diagnostic item or the type is not registered, for
instance when compiling with `#[no_std]`. All following examples are based on instance when compiling with `#[no_std]`.
[`DefId`]s and their usage. All the following examples are based on [`DefId`]s and their usage.
### Example: Checking for a type ### Example: Checking for a type
```rust ```rust
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
@ -96,6 +111,7 @@ fn example_1(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
``` ```
### Example: Checking for a trait implementation ### Example: Checking for a trait implementation
```rust ```rust
/// This example checks if a given [`DefId`] from a method is part of a trait /// This example checks if a given [`DefId`] from a method is part of a trait
/// implementation defined by a diagnostic item. /// implementation defined by a diagnostic item.
@ -112,6 +128,7 @@ fn is_diag_trait_item(
``` ```
### Associated Types ### Associated Types
Associated types of diagnostic items can be accessed indirectly by first Associated types of diagnostic items can be accessed indirectly by first
getting the [`DefId`] of the trait and then calling getting the [`DefId`] of the trait and then calling
[`TyCtxt::associated_items()`]. This returns an [`AssocItems`] object which can [`TyCtxt::associated_items()`]. This returns an [`AssocItems`] object which can
@ -119,13 +136,15 @@ be used for further checks. Checkout
[`clippy_utils::ty::get_iterator_item_ty()`] for an example usage of this. [`clippy_utils::ty::get_iterator_item_ty()`] for an example usage of this.
### Usage in Clippy ### Usage in Clippy
Clippy tries to use diagnostic items where possible and has developed some Clippy tries to use diagnostic items where possible and has developed some
wrapper and utility functions. Please also refer to its documentation when wrapper and utility functions. Please also refer to its documentation when
using diagnostic items in Clippy. (See [*Common tools for writing using diagnostic items in Clippy. (See [*Common tools for writing
lints*][clippy-Common-tools-for-writing-lints].) lints*][clippy-Common-tools-for-writing-lints].)
## Related issues ## Related issues
This lists some related issues. These are probably only interesting to people
These are probably only interesting to people
who really want to take a deep dive into the topic :) who really want to take a deep dive into the topic :)
* [rust#60966]: The Rust PR that introduced diagnostic items * [rust#60966]: The Rust PR that introduced diagnostic items