]> git.lizzy.rs Git - rust.git/blob - src/tools/rustfmt/src/parse/parser.rs
6983249c15d45404714abe79352ff8e39912f4c0
[rust.git] / src / tools / rustfmt / src / parse / parser.rs
1 use std::panic::{catch_unwind, AssertUnwindSafe};
2 use std::path::{Path, PathBuf};
3
4 use rustc_ast::token::TokenKind;
5 use rustc_ast::{ast, ptr};
6 use rustc_errors::Diagnostic;
7 use rustc_parse::{new_parser_from_file, parser::Parser as RawParser};
8 use rustc_span::{sym, Span};
9
10 use crate::attr::first_attr_value_str_by_name;
11 use crate::parse::session::ParseSess;
12 use crate::Input;
13
14 pub(crate) type DirectoryOwnership = rustc_expand::module::DirOwnership;
15 pub(crate) type ModulePathSuccess = rustc_expand::module::ModulePathSuccess;
16 pub(crate) type ModError<'a> = rustc_expand::module::ModError<'a>;
17
18 #[derive(Clone)]
19 pub(crate) struct Directory {
20     pub(crate) path: PathBuf,
21     pub(crate) ownership: DirectoryOwnership,
22 }
23
24 /// A parser for Rust source code.
25 pub(crate) struct Parser<'a> {
26     parser: RawParser<'a>,
27 }
28
29 /// A builder for the `Parser`.
30 #[derive(Default)]
31 pub(crate) struct ParserBuilder<'a> {
32     sess: Option<&'a ParseSess>,
33     input: Option<Input>,
34 }
35
36 impl<'a> ParserBuilder<'a> {
37     pub(crate) fn input(mut self, input: Input) -> ParserBuilder<'a> {
38         self.input = Some(input);
39         self
40     }
41
42     pub(crate) fn sess(mut self, sess: &'a ParseSess) -> ParserBuilder<'a> {
43         self.sess = Some(sess);
44         self
45     }
46
47     pub(crate) fn build(self) -> Result<Parser<'a>, ParserError> {
48         let sess = self.sess.ok_or(ParserError::NoParseSess)?;
49         let input = self.input.ok_or(ParserError::NoInput)?;
50
51         let parser = match Self::parser(sess.inner(), input) {
52             Ok(p) => p,
53             Err(db) => {
54                 if let Some(diagnostics) = db {
55                     sess.emit_diagnostics(diagnostics);
56                     return Err(ParserError::ParserCreationError);
57                 }
58                 return Err(ParserError::ParsePanicError);
59             }
60         };
61
62         Ok(Parser { parser })
63     }
64
65     fn parser(
66         sess: &'a rustc_session::parse::ParseSess,
67         input: Input,
68     ) -> Result<rustc_parse::parser::Parser<'a>, Option<Vec<Diagnostic>>> {
69         match input {
70             Input::File(ref file) => catch_unwind(AssertUnwindSafe(move || {
71                 new_parser_from_file(sess, file, None)
72             }))
73             .map_err(|_| None),
74             Input::Text(text) => rustc_parse::maybe_new_parser_from_source_str(
75                 sess,
76                 rustc_span::FileName::Custom("stdin".to_owned()),
77                 text,
78             )
79             .map_err(Some),
80         }
81     }
82 }
83
84 #[derive(Debug, PartialEq)]
85 pub(crate) enum ParserError {
86     NoParseSess,
87     NoInput,
88     ParserCreationError,
89     ParseError,
90     ParsePanicError,
91 }
92
93 impl<'a> Parser<'a> {
94     pub(crate) fn submod_path_from_attr(attrs: &[ast::Attribute], path: &Path) -> Option<PathBuf> {
95         let path_sym = first_attr_value_str_by_name(attrs, sym::path)?;
96         let path_str = path_sym.as_str();
97
98         // On windows, the base path might have the form
99         // `\\?\foo\bar` in which case it does not tolerate
100         // mixed `/` and `\` separators, so canonicalize
101         // `/` to `\`.
102         #[cfg(windows)]
103         let path_str = path_str.replace("/", "\\");
104
105         Some(path.join(path_str))
106     }
107
108     pub(crate) fn parse_file_as_module(
109         sess: &'a ParseSess,
110         path: &Path,
111         span: Span,
112     ) -> Result<(Vec<ast::Attribute>, Vec<ptr::P<ast::Item>>, Span), ParserError> {
113         let result = catch_unwind(AssertUnwindSafe(|| {
114             let mut parser = new_parser_from_file(sess.inner(), path, Some(span));
115             match parser.parse_mod(&TokenKind::Eof) {
116                 Ok((a, i, ast::ModSpans { inner_span, inject_use_span: _ })) => Some((a, i, inner_span)),
117                 Err(mut e) => {
118                     e.emit();
119                     if sess.can_reset_errors() {
120                         sess.reset_errors();
121                     }
122                     None
123                 }
124             }
125         }));
126         match result {
127             Ok(Some(m)) if !sess.has_errors() => Ok(m),
128             Ok(Some(m)) if sess.can_reset_errors() => {
129                 sess.reset_errors();
130                 Ok(m)
131             }
132             Ok(_) => Err(ParserError::ParseError),
133             Err(..) if path.exists() => Err(ParserError::ParseError),
134             Err(_) => Err(ParserError::ParsePanicError),
135         }
136     }
137
138     pub(crate) fn parse_crate(
139         input: Input,
140         sess: &'a ParseSess,
141     ) -> Result<ast::Crate, ParserError> {
142         let krate = Parser::parse_crate_inner(input, sess)?;
143         if !sess.has_errors() {
144             return Ok(krate);
145         }
146
147         if sess.can_reset_errors() {
148             sess.reset_errors();
149             return Ok(krate);
150         }
151
152         Err(ParserError::ParseError)
153     }
154
155     fn parse_crate_inner(input: Input, sess: &'a ParseSess) -> Result<ast::Crate, ParserError> {
156         ParserBuilder::default()
157             .input(input)
158             .sess(sess)
159             .build()?
160             .parse_crate_mod()
161     }
162
163     fn parse_crate_mod(&mut self) -> Result<ast::Crate, ParserError> {
164         let mut parser = AssertUnwindSafe(&mut self.parser);
165
166         match catch_unwind(move || parser.parse_crate_mod()) {
167             Ok(Ok(k)) => Ok(k),
168             Ok(Err(mut db)) => {
169                 db.emit();
170                 Err(ParserError::ParseError)
171             }
172             Err(_) => Err(ParserError::ParsePanicError),
173         }
174     }
175 }