about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2012-02-17 14:15:09 -0800
committerBrian Anderson <banderson@mozilla.com>2012-02-17 16:00:39 -0800
commita5ede9d34533be86bab0fd5a255d527b2fd3cdc6 (patch)
treea3cd32118644e16698c988d4e093a673dd9eda93
parentf7f73c79ec0cca88fc6e3657f955307049cb5801 (diff)
downloadrust-a5ede9d34533be86bab0fd5a255d527b2fd3cdc6.tar.gz
rust-a5ede9d34533be86bab0fd5a255d527b2fd3cdc6.zip
rustdoc: Resolve imports and reexports
-rw-r--r--src/comp/driver/driver.rs20
-rw-r--r--src/comp/middle/resolve.rs51
-rw-r--r--src/rustdoc/astsrv.rs113
3 files changed, 148 insertions, 36 deletions
diff --git a/src/comp/driver/driver.rs b/src/comp/driver/driver.rs
index 53ba8c65bdf..40cf4e50472 100644
--- a/src/comp/driver/driver.rs
+++ b/src/comp/driver/driver.rs
@@ -440,17 +440,27 @@ fn build_session_options(match: getopts::match,
 
 fn build_session(sopts: @session::options, input: str,
                  demitter: diagnostic::emitter) -> session {
+    let codemap = codemap::new_codemap();
+    let diagnostic_handler =
+        diagnostic::mk_handler(some(demitter));
+    let span_diagnostic_handler =
+        diagnostic::mk_span_handler(diagnostic_handler, codemap);
+    build_session_(sopts, input, codemap, demitter,
+                   span_diagnostic_handler)
+}
+
+fn build_session_(
+    sopts: @session::options, input: str,
+    codemap: codemap::codemap,
+    demitter: diagnostic::emitter,
+    span_diagnostic_handler: diagnostic::span_handler
+) -> session {
     let target_cfg = build_target_config(sopts, demitter);
     let cstore = cstore::mk_cstore();
     let filesearch = filesearch::mk_filesearch(
         sopts.maybe_sysroot,
         sopts.target_triple,
         sopts.addl_lib_search_paths);
-    let codemap = codemap::new_codemap();
-    let diagnostic_handler =
-        diagnostic::mk_handler(some(demitter));
-    let span_diagnostic_handler =
-        diagnostic::mk_span_handler(diagnostic_handler, codemap);
     @{targ_cfg: target_cfg,
       opts: sopts,
       cstore: cstore,
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index 1f68bb4a25e..c4e1923fc29 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -19,7 +19,7 @@ import std::list::{list, nil, cons};
 import option::{is_none, is_some};
 import syntax::print::pprust::*;
 
-export resolve_crate;
+export resolve_crate, resolve_crate_reexports;
 export def_map, ext_map, exp_map, impl_map;
 export _impl, iscopes, method_info;
 
@@ -155,24 +155,7 @@ enum ns_value_type { ns_a_enum, ns_any_value, }
 
 fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
    {def_map: def_map, exp_map: exp_map, impl_map: impl_map} {
-    let e =
-        @{cstore: sess.cstore,
-          def_map: new_int_hash(),
-          ast_map: amap,
-          imports: new_int_hash(),
-          exp_map: new_str_hash(),
-          mod_map: new_int_hash(),
-          block_map: new_int_hash(),
-          ext_map: new_def_hash(),
-          impl_map: new_int_hash(),
-          impl_cache: new_def_hash(),
-          ext_cache: new_ext_hash(),
-          used_imports: {mutable track: false, mutable data:  []},
-          mutable reported: [],
-          mutable ignored_imports: [],
-          mutable current_tp: none,
-          mutable resolve_unexported: false,
-          sess: sess};
+    let e = create_env(sess, amap);
     map_crate(e, crate);
     resolve_imports(*e);
     check_exports(e);
@@ -187,6 +170,36 @@ fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
     ret {def_map: e.def_map, exp_map: e.exp_map, impl_map: e.impl_map};
 }
 
+// Used by rustdoc
+fn resolve_crate_reexports(sess: session, amap: ast_map::map,
+                           crate: @ast::crate) -> exp_map {
+    let e = create_env(sess, amap);
+    map_crate(e, crate);
+    resolve_imports(*e);
+    check_exports(e);
+    ret e.exp_map;
+}
+
+fn create_env(sess: session, amap: ast_map::map) -> @env {
+    @{cstore: sess.cstore,
+      def_map: new_int_hash(),
+      ast_map: amap,
+      imports: new_int_hash(),
+      exp_map: new_str_hash(),
+      mod_map: new_int_hash(),
+      block_map: new_int_hash(),
+      ext_map: new_def_hash(),
+      impl_map: new_int_hash(),
+      impl_cache: new_def_hash(),
+      ext_cache: new_ext_hash(),
+      used_imports: {mutable track: false, mutable data:  []},
+      mutable reported: [],
+      mutable ignored_imports: [],
+      mutable current_tp: none,
+      mutable resolve_unexported: false,
+      sess: sess}
+}
+
 // Locate all modules and imports and index them, so that the next passes can
 // resolve through them.
 fn map_crate(e: @env, c: @ast::crate) {
diff --git a/src/rustdoc/astsrv.rs b/src/rustdoc/astsrv.rs
index 439bfd81dc7..3c6405d08c6 100644
--- a/src/rustdoc/astsrv.rs
+++ b/src/rustdoc/astsrv.rs
@@ -10,11 +10,14 @@
 import rustc::driver::session;
 import rustc::driver::driver;
 import rustc::driver::diagnostic;
+import rustc::driver::diagnostic::handler;
 import rustc::syntax::ast;
+import rustc::syntax::codemap;
 import rustc::middle::ast_map;
 import rustc::back::link;
 import rustc::util::filesearch;
 import rustc::front;
+import rustc::middle::resolve;
 
 export ctxt;
 export ctxt_handler;
@@ -25,7 +28,8 @@ export exec;
 
 type ctxt = {
     ast: @ast::crate,
-    ast_map: ast_map::map
+    ast_map: ast_map::map,
+    exp_map: resolve::exp_map
 };
 
 type ctxt_handler<T> = fn~(ctxt: ctxt) -> T;
@@ -35,36 +39,43 @@ type srv = {
 };
 
 fn mk_srv_from_str(source: str) -> srv {
-    let sess = build_session();
+    let (sess, ignore_errors) = build_session();
     {
-        ctxt: build_ctxt(sess, parse::from_str_sess(sess, source))
+        ctxt: build_ctxt(sess, parse::from_str_sess(sess, source),
+                         ignore_errors)
     }
 }
 
 fn mk_srv_from_file(file: str) -> srv {
-    let sess = build_session();
+    let (sess, ignore_errors) = build_session();
     {
-        ctxt: build_ctxt(sess, parse::from_file_sess(sess, file))
+        ctxt: build_ctxt(sess, parse::from_file_sess(sess, file),
+                         ignore_errors)
     }
 }
 
-fn build_ctxt(sess: session::session, ast: @ast::crate) -> ctxt {
+fn build_ctxt(sess: session::session, ast: @ast::crate,
+              ignore_errors: @mutable bool) -> ctxt {
 
     import rustc::front::config;
 
     let ast = config::strip_unconfigured_items(ast);
     let ast = front::test::modify_for_testing(sess, ast);
     let ast_map = ast_map::map_crate(*ast);
+    *ignore_errors = true;
+    let exp_map = resolve::resolve_crate_reexports(sess, ast_map, ast);
+    *ignore_errors = false;
 
     {
         ast: ast,
         ast_map: ast_map,
+        exp_map: exp_map
     }
 }
 
 // FIXME: this whole structure should not be duplicated here. makes it
 // painful to add or remove options.
-fn build_session() -> session::session {
+fn build_session() -> (session::session, @mutable bool) {
     let sopts: @session::options = @{
         crate_type: session::lib_crate,
         static: false,
@@ -89,7 +100,73 @@ fn build_session() -> session::session {
         monomorphize: false,
         warn_unused_imports: false
     };
-    driver::build_session(sopts, ".", diagnostic::emit)
+
+    let codemap = codemap::new_codemap();
+    let error_handlers = build_error_handlers(codemap);
+    let {emitter, span_handler, ignore_errors} = error_handlers;
+
+    let session = driver::build_session_(sopts, ".", codemap, emitter,
+                                         span_handler);
+    (session, ignore_errors)
+}
+
+type error_handlers = {
+    emitter: diagnostic::emitter,
+    span_handler: diagnostic::span_handler,
+    ignore_errors: @mutable bool
+};
+
+// Build a custom error handler that will allow us to ignore non-fatal
+// errors
+fn build_error_handlers(
+    codemap: codemap::codemap
+) -> error_handlers {
+
+    type diagnostic_handler = {
+        inner: diagnostic::handler,
+        ignore_errors: @mutable bool
+    };
+
+    impl of diagnostic::handler for diagnostic_handler {
+        fn fatal(msg: str) -> ! { self.inner.fatal(msg) }
+        fn err(msg: str) { self.inner.err(msg) }
+        fn bump_err_count() {
+            if !(*self.ignore_errors) {
+                self.inner.bump_err_count();
+            }
+        }
+        fn has_errors() -> bool { self.inner.has_errors() }
+        fn abort_if_errors() { self.inner.abort_if_errors() }
+        fn warn(msg: str) { self.inner.warn(msg) }
+        fn note(msg: str) { self.inner.note(msg) }
+        fn bug(msg: str) -> ! { self.inner.bug(msg) }
+        fn unimpl(msg: str) -> ! { self.inner.unimpl(msg) }
+        fn emit(cmsp: option<(codemap::codemap, codemap::span)>,
+                msg: str, lvl: diagnostic::level) {
+            self.inner.emit(cmsp, msg, lvl)
+        }
+    }
+
+    let ignore_errors = @mutable false;
+    let emitter = fn@(cmsp: option<(codemap::codemap, codemap::span)>,
+                       msg: str, lvl: diagnostic::level) {
+        if !(*ignore_errors) {
+            diagnostic::emit(cmsp, msg, lvl);
+        }
+    };
+    let inner_handler = diagnostic::mk_handler(some(emitter));
+    let handler = {
+        inner: inner_handler,
+        ignore_errors: ignore_errors
+    };
+    let span_handler = diagnostic::mk_span_handler(
+        handler as diagnostic::handler, codemap);
+
+    {
+        emitter: emitter,
+        span_handler: span_handler,
+        ignore_errors: ignore_errors
+    }
 }
 
 #[test]
@@ -111,14 +188,12 @@ fn srv_should_build_ast_map() {
 }
 
 #[test]
-#[ignore]
 fn srv_should_build_reexport_map() {
-    // FIXME
-    /*let source = "import a::b; export b; mod a { mod b { } }";
+    let source = "import a::b; export b; mod a { mod b { } }";
     let srv = mk_srv_from_str(source);
     exec(srv) {|ctxt|
         assert ctxt.exp_map.size() != 0u
-    };*/
+    };
 }
 
 #[test]
@@ -137,6 +212,20 @@ fn srv_should_resolve_core_crate() {
     mk_srv_from_str(source);
 }
 
+#[test]
+fn srv_should_resolve_non_existant_imports() {
+    // We want to ignore things we can't resolve. Shouldn't
+    // need to be able to find external crates to create docs.
+    let source = "import wooboo; fn a() { }";
+    mk_srv_from_str(source);
+}
+
+#[test]
+fn srv_sholud_resolve_non_existant_uses() {
+    let source = "use forble; fn a() { }";
+    mk_srv_from_str(source);
+}
+
 fn exec<T>(
     srv: srv,
     f: fn~(ctxt: ctxt) -> T