about summary refs log tree commit diff
path: root/src/modules.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules.rs')
-rw-r--r--src/modules.rs286
1 files changed, 107 insertions, 179 deletions
diff --git a/src/modules.rs b/src/modules.rs
index e7a2e21179d..9f8dabbfaf4 100644
--- a/src/modules.rs
+++ b/src/modules.rs
@@ -2,24 +2,25 @@ use std::borrow::Cow;
 use std::collections::BTreeMap;
 use std::path::{Path, PathBuf};
 
-use rustc_errors::PResult;
-use rustc_parse::{new_sub_parser_from_file, parser, DirectoryOwnership};
-use rustc_session::parse::ParseSess;
+use rustc_ast::ast;
+use rustc_ast::visit::Visitor;
 use rustc_span::symbol::{sym, Symbol};
-use rustc_span::{source_map, Span, DUMMY_SP};
-use syntax::ast;
-use syntax::token::TokenKind;
-use syntax::visit::Visitor;
 
 use crate::attr::MetaVisitor;
 use crate::config::FileName;
 use crate::items::is_mod_decl;
+use crate::syntux::parser::{Directory, DirectoryOwnership, ModulePathSuccess, Parser};
+use crate::syntux::session::ParseSess;
 use crate::utils::contains_skip;
 
 mod visitor;
 
 type FileModMap<'ast> = BTreeMap<FileName, Cow<'ast, ast::Mod>>;
 
+lazy_static! {
+    static ref CFG_IF: Symbol = Symbol::intern("cfg_if");
+}
+
 /// Maps each module to the corresponding file.
 pub(crate) struct ModResolver<'ast, 'sess> {
     parse_sess: &'sess ParseSess,
@@ -29,24 +30,9 @@ pub(crate) struct ModResolver<'ast, 'sess> {
 }
 
 #[derive(Clone)]
-struct Directory {
-    path: PathBuf,
-    ownership: DirectoryOwnership,
-}
-
-impl<'a> Directory {
-    fn to_syntax_directory(&'a self) -> rustc_parse::Directory<'a> {
-        rustc_parse::Directory {
-            path: Cow::Borrowed(&self.path),
-            ownership: self.ownership.clone(),
-        }
-    }
-}
-
-#[derive(Clone)]
 enum SubModKind<'a, 'ast> {
     /// `mod foo;`
-    External(PathBuf, DirectoryOwnership),
+    External(PathBuf, DirectoryOwnership, Cow<'ast, ast::Mod>),
     /// `mod foo;` with multiple sources.
     MultiExternal(Vec<(PathBuf, DirectoryOwnership, Cow<'ast, ast::Mod>)>),
     /// `#[path = "..."] mod foo {}`
@@ -78,12 +64,9 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
         mut self,
         krate: &'ast ast::Crate,
     ) -> Result<FileModMap<'ast>, String> {
-        let root_filename = self.parse_sess.source_map().span_to_filename(krate.span);
+        let root_filename = self.parse_sess.span_to_filename(krate.span);
         self.directory.path = match root_filename {
-            source_map::FileName::Real(ref path) => path
-                .parent()
-                .expect("Parent directory should exists")
-                .to_path_buf(),
+            FileName::Real(ref p) => p.parent().unwrap_or(Path::new("")).to_path_buf(),
             _ => PathBuf::new(),
         };
 
@@ -93,14 +76,13 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
         }
 
         self.file_map
-            .insert(root_filename.into(), Cow::Borrowed(&krate.module));
+            .insert(root_filename, Cow::Borrowed(&krate.module));
         Ok(self.file_map)
     }
 
     /// Visit `cfg_if` macro and look for module declarations.
     fn visit_cfg_if(&mut self, item: Cow<'ast, ast::Item>) -> Result<(), String> {
-        let mut visitor =
-            visitor::CfgIfVisitor::new(self.parse_sess, self.directory.to_syntax_directory());
+        let mut visitor = visitor::CfgIfVisitor::new(self.parse_sess);
         visitor.visit_item(&item);
         for module_item in visitor.mods() {
             if let ast::ItemKind::Mod(ref sub_mod) = module_item.item.kind {
@@ -168,7 +150,6 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
             // mod foo;
             // Look for an extern file.
             self.find_external_module(item.ident, &item.attrs, sub_mod)
-                .map(Some)
         } else {
             // An internal module (`mod foo { /* ... */ }`);
             if let Some(path) = find_path_value(&item.attrs) {
@@ -183,15 +164,19 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
     fn insert_sub_mod(
         &mut self,
         sub_mod_kind: SubModKind<'c, 'ast>,
-        sub_mod: Cow<'ast, ast::Mod>,
+        _sub_mod: Cow<'ast, ast::Mod>,
     ) -> Result<(), String> {
         match sub_mod_kind {
-            SubModKind::External(mod_path, _) => {
-                self.file_map.insert(FileName::Real(mod_path), sub_mod);
+            SubModKind::External(mod_path, _, sub_mod) => {
+                self.file_map
+                    .entry(FileName::Real(mod_path))
+                    .or_insert(sub_mod);
             }
             SubModKind::MultiExternal(mods) => {
                 for (mod_path, _, sub_mod) in mods {
-                    self.file_map.insert(FileName::Real(mod_path), sub_mod);
+                    self.file_map
+                        .entry(FileName::Real(mod_path))
+                        .or_insert(sub_mod);
                 }
             }
             _ => (),
@@ -205,7 +190,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
         sub_mod_kind: SubModKind<'c, 'ast>,
     ) -> Result<(), String> {
         match sub_mod_kind {
-            SubModKind::External(mod_path, directory_ownership) => {
+            SubModKind::External(mod_path, directory_ownership, sub_mod) => {
                 let directory = Directory {
                     path: mod_path.parent().unwrap().to_path_buf(),
                     ownership: directory_ownership,
@@ -257,48 +242,87 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
         mod_name: ast::Ident,
         attrs: &[ast::Attribute],
         sub_mod: &Cow<'ast, ast::Mod>,
-    ) -> Result<SubModKind<'c, 'ast>, String> {
-        if let Some(path) = parser::Parser::submod_path_from_attr(attrs, &self.directory.path) {
-            return Ok(SubModKind::External(
-                path,
-                DirectoryOwnership::Owned { relative: None },
-            ));
-        }
-
-        // Look for nested path, like `#[cfg_attr(feature = "foo", path = "bar.rs")]`.
-        let mut mods_outside_ast = self
-            .find_mods_ouside_of_ast(attrs, sub_mod)
-            .unwrap_or(vec![]);
-
+    ) -> Result<Option<SubModKind<'c, 'ast>>, String> {
         let relative = match self.directory.ownership {
             DirectoryOwnership::Owned { relative } => relative,
             DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
         };
-        match parser::Parser::default_submod_path(
-            mod_name,
-            relative,
-            &self.directory.path,
-            self.parse_sess.source_map(),
-        )
-        .result
+        if let Some(path) = Parser::submod_path_from_attr(attrs, &self.directory.path) {
+            if self.parse_sess.is_file_parsed(&path) {
+                return Ok(None);
+            }
+            return match Parser::parse_file_as_module(self.parse_sess, &path, sub_mod.inner) {
+                Some(m) => Ok(Some(SubModKind::External(
+                    path,
+                    DirectoryOwnership::Owned { relative: None },
+                    Cow::Owned(m),
+                ))),
+                None => Err(format!(
+                    "Failed to find module {} in {:?} {:?}",
+                    mod_name, self.directory.path, relative,
+                )),
+            };
+        }
+
+        // Look for nested path, like `#[cfg_attr(feature = "foo", path = "bar.rs")]`.
+        let mut mods_outside_ast = self.find_mods_outside_of_ast(attrs, sub_mod);
+
+        match self
+            .parse_sess
+            .default_submod_path(mod_name, relative, &self.directory.path)
+            .result
         {
-            Ok(parser::ModulePathSuccess {
-                path,
-                directory_ownership,
-                ..
-            }) => Ok(if mods_outside_ast.is_empty() {
-                SubModKind::External(path, directory_ownership)
-            } else {
-                mods_outside_ast.push((path, directory_ownership, sub_mod.clone()));
-                SubModKind::MultiExternal(mods_outside_ast)
-            }),
-            Err(_) if !mods_outside_ast.is_empty() => {
-                Ok(SubModKind::MultiExternal(mods_outside_ast))
+            Ok(ModulePathSuccess {
+                path, ownership, ..
+            }) => {
+                let outside_mods_empty = mods_outside_ast.is_empty();
+                let should_insert = !mods_outside_ast
+                    .iter()
+                    .any(|(outside_path, _, _)| outside_path == &path);
+                if self.parse_sess.is_file_parsed(&path) {
+                    if outside_mods_empty {
+                        return Ok(None);
+                    } else {
+                        if should_insert {
+                            mods_outside_ast.push((path, ownership, sub_mod.clone()));
+                        }
+                        return Ok(Some(SubModKind::MultiExternal(mods_outside_ast)));
+                    }
+                }
+                match Parser::parse_file_as_module(self.parse_sess, &path, sub_mod.inner) {
+                    Some(m) if outside_mods_empty => {
+                        Ok(Some(SubModKind::External(path, ownership, Cow::Owned(m))))
+                    }
+                    Some(m) => {
+                        mods_outside_ast.push((path.clone(), ownership, Cow::Owned(m)));
+                        if should_insert {
+                            mods_outside_ast.push((path, ownership, sub_mod.clone()));
+                        }
+                        Ok(Some(SubModKind::MultiExternal(mods_outside_ast)))
+                    }
+                    None if outside_mods_empty => Err(format!(
+                        "Failed to find module {} in {:?} {:?}",
+                        mod_name, self.directory.path, relative,
+                    )),
+                    None => {
+                        if should_insert {
+                            mods_outside_ast.push((path, ownership, sub_mod.clone()));
+                        }
+                        Ok(Some(SubModKind::MultiExternal(mods_outside_ast)))
+                    }
+                }
+            }
+            Err(mut e) if !mods_outside_ast.is_empty() => {
+                e.cancel();
+                Ok(Some(SubModKind::MultiExternal(mods_outside_ast)))
+            }
+            Err(mut e) => {
+                e.cancel();
+                Err(format!(
+                    "Failed to find module {} in {:?} {:?}",
+                    mod_name, self.directory.path, relative,
+                ))
             }
-            Err(_) => Err(format!(
-                "Failed to find module {} in {:?} {:?}",
-                mod_name, self.directory.path, relative,
-            )),
         }
     }
 
@@ -323,21 +347,7 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
         }
     }
 
-    fn find_mods_ouside_of_ast(
-        &self,
-        attrs: &[ast::Attribute],
-        sub_mod: &Cow<'ast, ast::Mod>,
-    ) -> Option<Vec<(PathBuf, DirectoryOwnership, Cow<'ast, ast::Mod>)>> {
-        use std::panic::{catch_unwind, AssertUnwindSafe};
-        Some(
-            catch_unwind(AssertUnwindSafe(|| {
-                self.find_mods_ouside_of_ast_inner(attrs, sub_mod)
-            }))
-            .ok()?,
-        )
-    }
-
-    fn find_mods_ouside_of_ast_inner(
+    fn find_mods_outside_of_ast(
         &self,
         attrs: &[ast::Attribute],
         sub_mod: &Cow<'ast, ast::Mod>,
@@ -356,14 +366,8 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
             if !actual_path.exists() {
                 continue;
             }
-            let file_name = rustc_span::FileName::Real(actual_path.clone());
-            if self
-                .parse_sess
-                .source_map()
-                .get_source_file(&file_name)
-                .is_some()
-            {
-                // If the specfied file is already parsed, then we just use that.
+            if self.parse_sess.is_file_parsed(&actual_path) {
+                // If the specified file is already parsed, then we just use that.
                 result.push((
                     actual_path,
                     DirectoryOwnership::Owned { relative: None },
@@ -371,32 +375,12 @@ impl<'ast, 'sess, 'c> ModResolver<'ast, 'sess> {
                 ));
                 continue;
             }
-            let mut parser = new_sub_parser_from_file(
-                self.parse_sess,
-                &actual_path,
-                self.directory.ownership,
-                None,
-                DUMMY_SP,
-            );
-            parser.cfg_mods = false;
-            let lo = parser.token.span;
-            // FIXME(topecongiro) Format inner attributes (#3606).
-            let _mod_attrs = match parse_inner_attributes(&mut parser) {
-                Ok(attrs) => attrs,
-                Err(mut e) => {
-                    e.cancel();
-                    parser.sess.span_diagnostic.reset_err_count();
-                    continue;
-                }
-            };
-            let m = match parse_mod_items(&mut parser, lo) {
-                Ok(m) => m,
-                Err(mut e) => {
-                    e.cancel();
-                    parser.sess.span_diagnostic.reset_err_count();
-                    continue;
-                }
+            let m = match Parser::parse_file_as_module(self.parse_sess, &actual_path, sub_mod.inner)
+            {
+                Some(m) => m,
+                None => continue,
             };
+
             result.push((
                 actual_path,
                 DirectoryOwnership::Owned { relative: None },
@@ -422,67 +406,11 @@ fn find_path_value(attrs: &[ast::Attribute]) -> Option<Symbol> {
     attrs.iter().flat_map(path_value).next()
 }
 
-// FIXME(topecongiro) Use the method from libsyntax[1] once it become public.
-//
-// [1] https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/attr.rs
-fn parse_inner_attributes<'a>(parser: &mut parser::Parser<'a>) -> PResult<'a, Vec<ast::Attribute>> {
-    let mut attrs: Vec<ast::Attribute> = vec![];
-    loop {
-        match parser.token.kind {
-            TokenKind::Pound => {
-                // Don't even try to parse if it's not an inner attribute.
-                if !parser.look_ahead(1, |t| t == &TokenKind::Not) {
-                    break;
-                }
-
-                let attr = parser.parse_attribute(true)?;
-                assert_eq!(attr.style, ast::AttrStyle::Inner);
-                attrs.push(attr);
-            }
-            TokenKind::DocComment(s) => {
-                // we need to get the position of this token before we bump.
-                let attr = syntax::attr::mk_doc_comment(
-                    syntax::util::comments::doc_comment_style(&s.as_str()),
-                    s,
-                    parser.token.span,
-                );
-                if attr.style == ast::AttrStyle::Inner {
-                    attrs.push(attr);
-                    parser.bump();
-                } else {
-                    break;
-                }
-            }
-            _ => break,
-        }
-    }
-    Ok(attrs)
-}
-
-fn parse_mod_items<'a>(parser: &mut parser::Parser<'a>, inner_lo: Span) -> PResult<'a, ast::Mod> {
-    let mut items = vec![];
-    while let Some(item) = parser.parse_item()? {
-        items.push(item);
-    }
-
-    let hi = if parser.token.span.is_dummy() {
-        inner_lo
-    } else {
-        parser.prev_span
-    };
-
-    Ok(ast::Mod {
-        inner: inner_lo.to(hi),
-        items,
-        inline: false,
-    })
-}
-
 fn is_cfg_if(item: &ast::Item) -> bool {
     match item.kind {
-        ast::ItemKind::Mac(ref mac) => {
+        ast::ItemKind::MacCall(ref mac) => {
             if let Some(first_segment) = mac.path.segments.first() {
-                if first_segment.ident.name == Symbol::intern("cfg_if") {
+                if first_segment.ident.name == *CFG_IF {
                     return true;
                 }
             }