From a5ede9d34533be86bab0fd5a255d527b2fd3cdc6 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 17 Feb 2012 14:15:09 -0800 Subject: [PATCH] rustdoc: Resolve imports and reexports --- src/comp/driver/driver.rs | 20 +++++-- src/comp/middle/resolve.rs | 51 ++++++++++------- src/rustdoc/astsrv.rs | 113 +++++++++++++++++++++++++++++++++---- 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 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 @@ type ctxt = { ast: @ast::crate, - ast_map: ast_map::map + ast_map: ast_map::map, + exp_map: resolve::exp_map }; type ctxt_handler = fn~(ctxt: ctxt) -> T; @@ -35,36 +39,43 @@ }; 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( srv: srv, f: fn~(ctxt: ctxt) -> T -- GitLab