1 use crate::tests::{matches_codepattern, string_to_stream, with_error_checking_parse};
3 use rustc_ast_pretty::pprust::item_to_string;
4 use rustc_errors::PResult;
5 use rustc_parse::new_parser_from_source_str;
6 use rustc_session::parse::ParseSess;
7 use rustc_span::source_map::FilePathMapping;
8 use rustc_span::symbol::{kw, sym, Symbol};
9 use rustc_span::{BytePos, FileName, Pos, Span};
10 use syntax::ast::{self, Name, PatKind};
12 use syntax::token::{self, Token};
13 use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree};
15 use syntax::with_default_globals;
17 use std::path::PathBuf;
19 fn sess() -> ParseSess {
20 ParseSess::new(FilePathMapping::empty())
25 /// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and `Err`
26 /// when a syntax error occurred.
27 fn parse_item_from_source_str(
31 ) -> PResult<'_, Option<P<ast::Item>>> {
32 new_parser_from_source_str(sess, name, source).parse_item()
35 // Produces a `rustc_span::span`.
36 fn sp(a: u32, b: u32) -> Span {
37 Span::with_root_ctxt(BytePos(a), BytePos(b))
40 /// Parses a string, return an expression.
41 fn string_to_expr(source_str: String) -> P<ast::Expr> {
42 with_error_checking_parse(source_str, &sess(), |p| p.parse_expr())
45 /// Parses a string, returns an item.
46 fn string_to_item(source_str: String) -> Option<P<ast::Item>> {
47 with_error_checking_parse(source_str, &sess(), |p| p.parse_item())
52 fn bad_path_expr_1() {
53 with_default_globals(|| {
54 string_to_expr("::abc::def::return".to_string());
58 // Checks the token-tree-ization of macros.
60 fn string_to_tts_macro() {
61 with_default_globals(|| {
63 string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).trees().collect();
64 let tts: &[TokenTree] = &tts[..];
67 [TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }), TokenTree::Token(Token { kind: token::Not, .. }), TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), TokenTree::Delimited(_, macro_delim, macro_tts)]
68 if name_macro_rules == &sym::macro_rules && name_zip.as_str() == "zip" =>
70 let tts = ¯o_tts.trees().collect::<Vec<_>>();
72 [TokenTree::Delimited(_, first_delim, first_tts), TokenTree::Token(Token { kind: token::FatArrow, .. }), TokenTree::Delimited(_, second_delim, second_tts)]
73 if macro_delim == &token::Paren =>
75 let tts = &first_tts.trees().collect::<Vec<_>>();
77 [TokenTree::Token(Token { kind: token::Dollar, .. }), TokenTree::Token(Token { kind: token::Ident(name, false), .. })]
78 if first_delim == &token::Paren && name.as_str() == "a" => {}
79 _ => panic!("value 3: {:?} {:?}", first_delim, first_tts),
81 let tts = &second_tts.trees().collect::<Vec<_>>();
83 [TokenTree::Token(Token { kind: token::Dollar, .. }), TokenTree::Token(Token { kind: token::Ident(name, false), .. })]
84 if second_delim == &token::Paren && name.as_str() == "a" => {}
85 _ => panic!("value 4: {:?} {:?}", second_delim, second_tts),
88 _ => panic!("value 2: {:?} {:?}", macro_delim, macro_tts),
91 _ => panic!("value: {:?}", tts),
97 fn string_to_tts_1() {
98 with_default_globals(|| {
99 let tts = string_to_stream("fn a (b : i32) { b; }".to_string());
101 let expected = TokenStream::new(vec![
102 TokenTree::token(token::Ident(kw::Fn, false), sp(0, 2)).into(),
103 TokenTree::token(token::Ident(Name::intern("a"), false), sp(3, 4)).into(),
104 TokenTree::Delimited(
105 DelimSpan::from_pair(sp(5, 6), sp(13, 14)),
106 token::DelimToken::Paren,
107 TokenStream::new(vec![
108 TokenTree::token(token::Ident(Name::intern("b"), false), sp(6, 7)).into(),
109 TokenTree::token(token::Colon, sp(8, 9)).into(),
110 TokenTree::token(token::Ident(sym::i32, false), sp(10, 13)).into(),
115 TokenTree::Delimited(
116 DelimSpan::from_pair(sp(15, 16), sp(20, 21)),
117 token::DelimToken::Brace,
118 TokenStream::new(vec![
119 TokenTree::token(token::Ident(Name::intern("b"), false), sp(17, 18)).into(),
120 TokenTree::token(token::Semi, sp(18, 19)).into(),
127 assert_eq!(tts, expected);
133 with_default_globals(|| {
134 let use_s = "use foo::bar::baz;";
135 let vitem = string_to_item(use_s.to_string()).unwrap();
136 let vitem_s = item_to_string(&vitem);
137 assert_eq!(&vitem_s[..], use_s);
139 let use_s = "use foo::bar as baz;";
140 let vitem = string_to_item(use_s.to_string()).unwrap();
141 let vitem_s = item_to_string(&vitem);
142 assert_eq!(&vitem_s[..], use_s);
147 fn parse_extern_crate() {
148 with_default_globals(|| {
149 let ex_s = "extern crate foo;";
150 let vitem = string_to_item(ex_s.to_string()).unwrap();
151 let vitem_s = item_to_string(&vitem);
152 assert_eq!(&vitem_s[..], ex_s);
154 let ex_s = "extern crate foo as bar;";
155 let vitem = string_to_item(ex_s.to_string()).unwrap();
156 let vitem_s = item_to_string(&vitem);
157 assert_eq!(&vitem_s[..], ex_s);
161 fn get_spans_of_pat_idents(src: &str) -> Vec<Span> {
162 let item = string_to_item(src.to_string()).unwrap();
164 struct PatIdentVisitor {
167 impl<'a> visit::Visitor<'a> for PatIdentVisitor {
168 fn visit_pat(&mut self, p: &'a ast::Pat) {
170 PatKind::Ident(_, ref ident, _) => {
171 self.spans.push(ident.span.clone());
174 visit::walk_pat(self, p);
179 let mut v = PatIdentVisitor { spans: Vec::new() };
180 visit::walk_item(&mut v, &item);
185 fn span_of_self_arg_pat_idents_are_correct() {
186 with_default_globals(|| {
188 "impl z { fn a (&self, &myarg: i32) {} }",
189 "impl z { fn a (&mut self, &myarg: i32) {} }",
190 "impl z { fn a (&'a self, &myarg: i32) {} }",
191 "impl z { fn a (self, &myarg: i32) {} }",
192 "impl z { fn a (self: Foo, &myarg: i32) {} }",
196 let spans = get_spans_of_pat_idents(src);
197 let (lo, hi) = (spans[0].lo(), spans[0].hi());
199 "self" == &src[lo.to_usize()..hi.to_usize()],
200 "\"{}\" != \"self\". src=\"{}\"",
201 &src[lo.to_usize()..hi.to_usize()],
210 with_default_globals(|| {
211 // just make sure that they parse....
212 string_to_expr("3 + 4".to_string());
213 string_to_expr("a::z.froob(b,&(987+3))".to_string());
219 with_default_globals(|| {
221 "pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
222 -> Result<Box<Writer>, String> {
225 (O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int
229 fn wb() -> c_int { O_WRONLY as c_int }
231 let mut fflags: c_int = wb();
239 fn crlf_doc_comments() {
240 with_default_globals(|| {
243 let name_1 = FileName::Custom("crlf_source_1".to_string());
244 let source = "/// doc comment\r\nfn foo() {}".to_string();
245 let item = parse_item_from_source_str(name_1, source, &sess).unwrap().unwrap();
246 let doc = item.attrs.iter().filter_map(|at| at.doc_str()).next().unwrap();
247 assert_eq!(doc.as_str(), "/// doc comment");
249 let name_2 = FileName::Custom("crlf_source_2".to_string());
250 let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string();
251 let item = parse_item_from_source_str(name_2, source, &sess).unwrap().unwrap();
252 let docs = item.attrs.iter().filter_map(|at| at.doc_str()).collect::<Vec<_>>();
253 let b: &[_] = &[Symbol::intern("/// doc comment"), Symbol::intern("/// line 2")];
254 assert_eq!(&docs[..], b);
256 let name_3 = FileName::Custom("clrf_source_3".to_string());
257 let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string();
258 let item = parse_item_from_source_str(name_3, source, &sess).unwrap().unwrap();
259 let doc = item.attrs.iter().filter_map(|at| at.doc_str()).next().unwrap();
260 assert_eq!(doc.as_str(), "/** doc comment\n * with CRLF */");
266 fn parse_expr_from_source_str(
270 ) -> PResult<'_, P<ast::Expr>> {
271 new_parser_from_source_str(sess, name, source).parse_expr()
274 with_default_globals(|| {
276 let expr = parse_expr_from_source_str(
277 PathBuf::from("foo").into(),
278 "foo!( fn main() { body } )".to_string(),
283 let tts: Vec<_> = match expr.kind {
284 ast::ExprKind::Mac(ref mac) => mac.args.inner_tokens().trees().collect(),
285 _ => panic!("not a macro"),
288 let span = tts.iter().rev().next().unwrap().span();
290 match sess.source_map().span_to_snippet(span) {
291 Ok(s) => assert_eq!(&s[..], "{ body }"),
292 Err(_) => panic!("could not get snippet"),
297 // This tests that when parsing a string (rather than a file) we don't try
298 // and read in a file for a module declaration and just parse a stub.
299 // See `recurse_into_file_modules` in the parser.
301 fn out_of_line_mod() {
302 with_default_globals(|| {
303 let item = parse_item_from_source_str(
304 PathBuf::from("foo").into(),
305 "mod foo { struct S; mod this_does_not_exist; }".to_owned(),
311 if let ast::ItemKind::Mod(ref m) = item.kind {
312 assert!(m.items.len() == 2);
321 assert_eq!(matches_codepattern("", ""), true);
322 assert_eq!(matches_codepattern("", "a"), false);
323 assert_eq!(matches_codepattern("a", ""), false);
324 assert_eq!(matches_codepattern("a", "a"), true);
325 assert_eq!(matches_codepattern("a b", "a \n\t\r b"), true);
326 assert_eq!(matches_codepattern("a b ", "a \n\t\r b"), true);
327 assert_eq!(matches_codepattern("a b", "a \n\t\r b "), false);
328 assert_eq!(matches_codepattern("a b", "a b"), true);
329 assert_eq!(matches_codepattern("ab", "a b"), false);
330 assert_eq!(matches_codepattern("a b", "ab"), true);
331 assert_eq!(matches_codepattern(" a b", "ab"), true);
335 fn pattern_whitespace() {
336 assert_eq!(matches_codepattern("", "\x0C"), false);
337 assert_eq!(matches_codepattern("a b ", "a \u{0085}\n\t\r b"), true);
338 assert_eq!(matches_codepattern("a b", "a \u{0085}\n\t\r b "), false);
342 fn non_pattern_whitespace() {
343 // These have the property 'White_Space' but not 'Pattern_White_Space'
344 assert_eq!(matches_codepattern("a b", "a\u{2002}b"), false);
345 assert_eq!(matches_codepattern("a b", "a\u{2002}b"), false);
346 assert_eq!(matches_codepattern("\u{205F}a b", "ab"), false);
347 assert_eq!(matches_codepattern("a \u{3000}b", "ab"), false);