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