]> git.proxmox.com Git - rustc.git/blob - src/doc/unstable-book/src/language-features/plugin.md
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / src / doc / unstable-book / src / language-features / plugin.md
1 # `plugin`
2
3 The tracking issue for this feature is: [#29597]
4
5 [#29597]: https://github.com/rust-lang/rust/issues/29597
6
7
8 This feature is part of "compiler plugins." It will often be used with the
9 [`plugin_registrar`] and `rustc_private` features.
10
11 [`plugin_registrar`]: plugin-registrar.md
12
13 ------------------------
14
15 `rustc` can load compiler plugins, which are user-provided libraries that
16 extend the compiler's behavior with new lint checks, etc.
17
18 A plugin is a dynamic library crate with a designated *registrar* function that
19 registers extensions with `rustc`. Other crates can load these extensions using
20 the crate attribute `#![plugin(...)]`. See the
21 `rustc_driver::plugin` documentation for more about the
22 mechanics of defining and loading a plugin.
23
24 In the vast majority of cases, a plugin should *only* be used through
25 `#![plugin]` and not through an `extern crate` item. Linking a plugin would
26 pull in all of librustc_ast and librustc as dependencies of your crate. This is
27 generally unwanted unless you are building another plugin.
28
29 The usual practice is to put compiler plugins in their own crate, separate from
30 any `macro_rules!` macros or ordinary Rust code meant to be used by consumers
31 of a library.
32
33 # Lint plugins
34
35 Plugins can extend [Rust's lint
36 infrastructure](../../reference/attributes/diagnostics.md#lint-check-attributes) with
37 additional checks for code style, safety, etc. Now let's write a plugin
38 [`lint-plugin-test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs)
39 that warns about any item named `lintme`.
40
41 ```rust,ignore (requires-stage-2)
42 #![feature(plugin_registrar)]
43 #![feature(box_syntax, rustc_private)]
44
45 extern crate rustc_ast;
46
47 // Load rustc as a plugin to get macros
48 extern crate rustc_driver;
49 #[macro_use]
50 extern crate rustc_lint;
51 #[macro_use]
52 extern crate rustc_session;
53
54 use rustc_driver::plugin::Registry;
55 use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
56 use rustc_ast::ast;
57 declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
58
59 declare_lint_pass!(Pass => [TEST_LINT]);
60
61 impl EarlyLintPass for Pass {
62 fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
63 if it.ident.name.as_str() == "lintme" {
64 cx.lint(TEST_LINT, |lint| {
65 lint.build("item is named 'lintme'").set_span(it.span).emit()
66 });
67 }
68 }
69 }
70
71 #[plugin_registrar]
72 pub fn plugin_registrar(reg: &mut Registry) {
73 reg.lint_store.register_lints(&[&TEST_LINT]);
74 reg.lint_store.register_early_pass(|| box Pass);
75 }
76 ```
77
78 Then code like
79
80 ```rust,ignore (requires-plugin)
81 #![feature(plugin)]
82 #![plugin(lint_plugin_test)]
83
84 fn lintme() { }
85 ```
86
87 will produce a compiler warning:
88
89 ```txt
90 foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default
91 foo.rs:4 fn lintme() { }
92 ^~~~~~~~~~~~~~~
93 ```
94
95 The components of a lint plugin are:
96
97 * one or more `declare_lint!` invocations, which define static `Lint` structs;
98
99 * a struct holding any state needed by the lint pass (here, none);
100
101 * a `LintPass`
102 implementation defining how to check each syntax element. A single
103 `LintPass` may call `span_lint` for several different `Lint`s, but should
104 register them all through the `get_lints` method.
105
106 Lint passes are syntax traversals, but they run at a late stage of compilation
107 where type information is available. `rustc`'s [built-in
108 lints](https://github.com/rust-lang/rust/blob/master/src/librustc_session/lint/builtin.rs)
109 mostly use the same infrastructure as lint plugins, and provide examples of how
110 to access type information.
111
112 Lints defined by plugins are controlled by the usual [attributes and compiler
113 flags](../../reference/attributes/diagnostics.md#lint-check-attributes), e.g.
114 `#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the
115 first argument to `declare_lint!`, with appropriate case and punctuation
116 conversion.
117
118 You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`,
119 including those provided by plugins loaded by `foo.rs`.