aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/attr.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-10-05 15:25:59 +0100
committerGitHub <[email protected]>2019-10-05 15:25:59 +0100
commitae6305b90c80eb919cfde985cba66975b6222ed2 (patch)
treede601daf3714c4bda937e7cad05d048b69d16e71 /crates/ra_hir/src/attr.rs
parentdbf869b4d2dac09df17609edf6e67c1611b71dc5 (diff)
parentc6303d9fee98232ac83a77f943c39d65c9c6b6db (diff)
Merge #1928
1928: Support `#[cfg(..)]` r=matklad a=oxalica This PR implement `#[cfg(..)]` conditional compilation. It read default cfg options from `rustc --print cfg` with also hard-coded `test` and `debug_assertion` enabled. Front-end settings are **not** included in this PR. There is also a known issue that inner control attributes are totally ignored. I think it is **not** a part of `cfg` and create a separated issue for it. #1949 Fixes #1920 Related: #1073 Co-authored-by: uHOOCCOOHu <[email protected]> Co-authored-by: oxalica <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/attr.rs')
-rw-r--r--crates/ra_hir/src/attr.rs80
1 files changed, 80 insertions, 0 deletions
diff --git a/crates/ra_hir/src/attr.rs b/crates/ra_hir/src/attr.rs
new file mode 100644
index 000000000..f67e80bfd
--- /dev/null
+++ b/crates/ra_hir/src/attr.rs
@@ -0,0 +1,80 @@
1//! A higher level attributes based on TokenTree, with also some shortcuts.
2
3use std::sync::Arc;
4
5use mbe::ast_to_token_tree;
6use ra_cfg::CfgOptions;
7use ra_syntax::{
8 ast::{self, AstNode, AttrsOwner},
9 SmolStr,
10};
11use tt::Subtree;
12
13use crate::{db::AstDatabase, path::Path, HirFileId, Source};
14
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub(crate) struct Attr {
17 pub(crate) path: Path,
18 pub(crate) input: Option<AttrInput>,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum AttrInput {
23 Literal(SmolStr),
24 TokenTree(Subtree),
25}
26
27impl Attr {
28 pub(crate) fn from_src(
29 Source { file_id, ast }: Source<ast::Attr>,
30 db: &impl AstDatabase,
31 ) -> Option<Attr> {
32 let path = Path::from_src(Source { file_id, ast: ast.path()? }, db)?;
33 let input = match ast.input() {
34 None => None,
35 Some(ast::AttrInput::Literal(lit)) => {
36 // FIXME: escape? raw string?
37 let value = lit.syntax().first_token()?.text().trim_matches('"').into();
38 Some(AttrInput::Literal(value))
39 }
40 Some(ast::AttrInput::TokenTree(tt)) => {
41 Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0))
42 }
43 };
44
45 Some(Attr { path, input })
46 }
47
48 pub(crate) fn from_attrs_owner(
49 file_id: HirFileId,
50 owner: &dyn AttrsOwner,
51 db: &impl AstDatabase,
52 ) -> Option<Arc<[Attr]>> {
53 let mut attrs = owner.attrs().peekable();
54 if attrs.peek().is_none() {
55 // Avoid heap allocation
56 return None;
57 }
58 Some(attrs.flat_map(|ast| Attr::from_src(Source { file_id, ast }, db)).collect())
59 }
60
61 pub(crate) fn is_simple_atom(&self, name: &str) -> bool {
62 // FIXME: Avoid cloning
63 self.path.as_ident().map_or(false, |s| s.to_string() == name)
64 }
65
66 pub(crate) fn as_cfg(&self) -> Option<&Subtree> {
67 if self.is_simple_atom("cfg") {
68 match &self.input {
69 Some(AttrInput::TokenTree(subtree)) => Some(subtree),
70 _ => None,
71 }
72 } else {
73 None
74 }
75 }
76
77 pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Option<bool> {
78 cfg_options.is_cfg_enabled(self.as_cfg()?)
79 }
80}