2012-12-03 16:48:01 -08:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2012-09-20 16:09:46 -07:00
|
|
|
/*!
|
|
|
|
Provides all access to AST-related, non-sendable info
|
|
|
|
|
|
|
|
Rustdoc is intended to be parallel, and the rustc AST is filled with
|
|
|
|
shared boxes. The AST service attempts to provide a single place to
|
|
|
|
query AST-related information, shielding the rest of Rustdoc from its
|
|
|
|
non-sendableness.
|
|
|
|
*/
|
2012-01-16 16:55:26 -08:00
|
|
|
|
2012-12-23 17:41:37 -05:00
|
|
|
use parse;
|
|
|
|
use util;
|
|
|
|
|
|
|
|
use core::oldcomm;
|
2012-12-29 17:38:20 -08:00
|
|
|
use core::vec;
|
2012-12-13 13:05:22 -08:00
|
|
|
use rustc::back::link;
|
2012-09-05 10:41:47 -07:00
|
|
|
use rustc::driver::driver;
|
2012-12-13 13:05:22 -08:00
|
|
|
use rustc::driver::session::Session;
|
|
|
|
use rustc::driver::session::{basic_options, options};
|
|
|
|
use rustc::driver::session;
|
|
|
|
use rustc::front;
|
|
|
|
use rustc::metadata::filesearch;
|
|
|
|
use std::map::HashMap;
|
2012-09-05 10:41:47 -07:00
|
|
|
use syntax::ast;
|
|
|
|
use syntax::ast_map;
|
2012-12-13 13:05:22 -08:00
|
|
|
use syntax::codemap;
|
|
|
|
use syntax::diagnostic::handler;
|
|
|
|
use syntax::diagnostic;
|
2012-12-23 17:41:37 -05:00
|
|
|
use syntax;
|
2012-01-16 16:55:26 -08:00
|
|
|
|
2012-11-19 18:00:12 -08:00
|
|
|
pub type Ctxt = {
|
2012-01-16 16:55:26 -08:00
|
|
|
ast: @ast::crate,
|
2012-07-18 10:14:28 -07:00
|
|
|
ast_map: ast_map::map
|
2012-01-16 16:55:26 -08:00
|
|
|
};
|
|
|
|
|
2012-09-18 16:48:40 -07:00
|
|
|
type SrvOwner<T> = fn(srv: Srv) -> T;
|
2012-11-19 18:00:12 -08:00
|
|
|
pub type CtxtHandler<T> = fn~(ctxt: Ctxt) -> T;
|
2012-11-19 18:48:46 -08:00
|
|
|
type Parser = fn~(Session, +s: ~str) -> @ast::crate;
|
2012-01-16 16:55:26 -08:00
|
|
|
|
2012-09-18 16:48:40 -07:00
|
|
|
enum Msg {
|
|
|
|
HandleRequest(fn~(Ctxt)),
|
|
|
|
Exit
|
2012-02-20 21:41:24 -08:00
|
|
|
}
|
|
|
|
|
2012-11-19 18:00:12 -08:00
|
|
|
pub enum Srv = {
|
2012-12-13 14:18:47 -08:00
|
|
|
ch: oldcomm::Chan<Msg>
|
2012-01-17 16:12:31 -08:00
|
|
|
};
|
2012-01-16 16:55:26 -08:00
|
|
|
|
2012-11-26 18:03:36 -08:00
|
|
|
impl Srv: Clone {
|
|
|
|
fn clone(&self) -> Srv { copy *self }
|
|
|
|
}
|
|
|
|
|
2012-11-19 18:00:12 -08:00
|
|
|
pub fn from_str<T>(source: ~str, owner: SrvOwner<T>) -> T {
|
2012-04-30 11:52:07 -07:00
|
|
|
run(owner, source, parse::from_str_sess)
|
2012-02-20 21:41:24 -08:00
|
|
|
}
|
2012-02-20 21:08:19 -08:00
|
|
|
|
2012-11-19 18:00:12 -08:00
|
|
|
pub fn from_file<T>(file: ~str, owner: SrvOwner<T>) -> T {
|
2012-08-24 15:28:43 -07:00
|
|
|
run(owner, file, |sess, f| parse::from_file_sess(sess, &Path(f)))
|
2012-02-20 21:41:24 -08:00
|
|
|
}
|
|
|
|
|
2012-09-18 16:48:40 -07:00
|
|
|
fn run<T>(owner: SrvOwner<T>, source: ~str, +parse: Parser) -> T {
|
2012-02-20 21:41:24 -08:00
|
|
|
|
2012-09-18 16:48:40 -07:00
|
|
|
let srv_ = Srv({
|
2012-12-12 19:17:31 -08:00
|
|
|
ch: do util::spawn_listener |move parse, po| {
|
2012-02-20 21:41:24 -08:00
|
|
|
act(po, source, parse);
|
|
|
|
}
|
|
|
|
});
|
2012-02-20 21:08:19 -08:00
|
|
|
|
2012-02-20 21:41:24 -08:00
|
|
|
let res = owner(srv_);
|
2012-12-13 14:18:47 -08:00
|
|
|
oldcomm::send(srv_.ch, Exit);
|
2012-09-18 22:43:54 -07:00
|
|
|
move res
|
2012-01-16 16:55:26 -08:00
|
|
|
}
|
|
|
|
|
2012-12-13 14:18:47 -08:00
|
|
|
fn act(po: oldcomm::Port<Msg>, source: ~str, parse: Parser) {
|
2012-07-18 10:14:28 -07:00
|
|
|
let sess = build_session();
|
2012-02-20 21:08:19 -08:00
|
|
|
|
2012-02-20 21:41:24 -08:00
|
|
|
let ctxt = build_ctxt(
|
|
|
|
sess,
|
2012-07-18 10:14:28 -07:00
|
|
|
parse(sess, source)
|
2012-02-20 21:41:24 -08:00
|
|
|
);
|
|
|
|
|
2012-03-22 08:39:41 -07:00
|
|
|
let mut keep_going = true;
|
2012-02-20 21:41:24 -08:00
|
|
|
while keep_going {
|
2012-12-13 14:18:47 -08:00
|
|
|
match oldcomm::recv(po) {
|
2012-09-18 16:48:40 -07:00
|
|
|
HandleRequest(f) => {
|
2012-02-20 21:41:24 -08:00
|
|
|
f(ctxt);
|
|
|
|
}
|
2012-09-18 16:48:40 -07:00
|
|
|
Exit => {
|
2012-02-20 21:41:24 -08:00
|
|
|
keep_going = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-20 21:08:19 -08:00
|
|
|
|
2012-12-11 13:50:04 -08:00
|
|
|
pub fn exec<T:Owned>(
|
2012-09-18 16:48:40 -07:00
|
|
|
srv: Srv,
|
|
|
|
+f: fn~(ctxt: Ctxt) -> T
|
2012-02-20 21:41:24 -08:00
|
|
|
) -> T {
|
2012-12-13 14:18:47 -08:00
|
|
|
let po = oldcomm::Port();
|
|
|
|
let ch = oldcomm::Chan(&po);
|
2012-09-18 16:48:40 -07:00
|
|
|
let msg = HandleRequest(fn~(move f, ctxt: Ctxt) {
|
2012-12-13 14:18:47 -08:00
|
|
|
oldcomm::send(ch, f(ctxt))
|
2012-02-20 21:41:24 -08:00
|
|
|
});
|
2012-12-13 14:18:47 -08:00
|
|
|
oldcomm::send(srv.ch, move msg);
|
|
|
|
oldcomm::recv(po)
|
2012-01-16 16:55:26 -08:00
|
|
|
}
|
|
|
|
|
2012-10-15 14:56:42 -07:00
|
|
|
fn build_ctxt(sess: Session,
|
2012-09-18 16:48:40 -07:00
|
|
|
ast: @ast::crate) -> Ctxt {
|
2012-01-18 15:48:09 -08:00
|
|
|
|
2012-09-07 18:08:21 -07:00
|
|
|
use rustc::front::config;
|
2012-01-18 15:48:09 -08:00
|
|
|
|
|
|
|
let ast = config::strip_unconfigured_items(ast);
|
2012-07-17 18:32:04 -07:00
|
|
|
let ast = syntax::ext::expand::expand_crate(sess.parse_sess,
|
|
|
|
sess.opts.cfg, ast);
|
2012-01-26 00:35:07 -08:00
|
|
|
let ast = front::test::modify_for_testing(sess, ast);
|
2012-05-21 22:57:43 -07:00
|
|
|
let ast_map = ast_map::map_crate(sess.diagnostic(), *ast);
|
2012-01-18 15:48:09 -08:00
|
|
|
|
2012-01-16 16:55:26 -08:00
|
|
|
{
|
|
|
|
ast: ast,
|
2012-01-26 00:35:07 -08:00
|
|
|
ast_map: ast_map,
|
2012-01-16 16:55:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-15 14:56:42 -07:00
|
|
|
fn build_session() -> Session {
|
2012-06-26 14:15:48 -07:00
|
|
|
let sopts: @options = basic_options();
|
2012-11-12 18:24:56 -08:00
|
|
|
let codemap = @codemap::CodeMap::new();
|
2012-02-17 14:15:09 -08:00
|
|
|
let error_handlers = build_error_handlers(codemap);
|
2012-07-18 10:14:28 -07:00
|
|
|
let {emitter, span_handler} = error_handlers;
|
2012-02-17 14:15:09 -08:00
|
|
|
|
2012-03-21 18:56:20 -04:00
|
|
|
let session = driver::build_session_(sopts, codemap, emitter,
|
2012-02-17 14:15:09 -08:00
|
|
|
span_handler);
|
2012-07-18 10:14:28 -07:00
|
|
|
session
|
2012-02-17 14:15:09 -08:00
|
|
|
}
|
|
|
|
|
2012-09-18 16:48:40 -07:00
|
|
|
type ErrorHandlers = {
|
2012-02-17 14:15:09 -08:00
|
|
|
emitter: diagnostic::emitter,
|
2012-07-18 10:14:28 -07:00
|
|
|
span_handler: diagnostic::span_handler
|
2012-02-17 14:15:09 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Build a custom error handler that will allow us to ignore non-fatal
|
|
|
|
// errors
|
|
|
|
fn build_error_handlers(
|
2012-11-12 16:56:39 -08:00
|
|
|
codemap: @codemap::CodeMap
|
2012-09-18 16:48:40 -07:00
|
|
|
) -> ErrorHandlers {
|
2012-02-17 14:15:09 -08:00
|
|
|
|
2012-09-18 16:48:40 -07:00
|
|
|
type DiagnosticHandler = {
|
2012-02-17 14:15:09 -08:00
|
|
|
inner: diagnostic::handler,
|
|
|
|
};
|
|
|
|
|
2012-09-18 16:48:40 -07:00
|
|
|
impl DiagnosticHandler: diagnostic::handler {
|
2012-09-28 12:22:33 -07:00
|
|
|
fn fatal(msg: &str) -> ! { self.inner.fatal(msg) }
|
|
|
|
fn err(msg: &str) { self.inner.err(msg) }
|
2012-02-17 14:15:09 -08:00
|
|
|
fn bump_err_count() {
|
2012-07-18 10:14:28 -07:00
|
|
|
self.inner.bump_err_count();
|
2012-02-17 14:15:09 -08:00
|
|
|
}
|
|
|
|
fn has_errors() -> bool { self.inner.has_errors() }
|
|
|
|
fn abort_if_errors() { self.inner.abort_if_errors() }
|
2012-09-28 12:22:33 -07:00
|
|
|
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) }
|
2012-11-12 16:56:39 -08:00
|
|
|
fn emit(cmsp: Option<(@codemap::CodeMap, codemap::span)>,
|
2012-09-28 12:22:33 -07:00
|
|
|
msg: &str, lvl: diagnostic::level) {
|
2012-02-17 14:15:09 -08:00
|
|
|
self.inner.emit(cmsp, msg, lvl)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-12 16:56:39 -08:00
|
|
|
let emitter = fn@(cmsp: Option<(@codemap::CodeMap, codemap::span)>,
|
2012-09-28 12:22:33 -07:00
|
|
|
msg: &str, lvl: diagnostic::level) {
|
2012-07-18 10:14:28 -07:00
|
|
|
diagnostic::emit(cmsp, msg, lvl);
|
2012-02-17 14:15:09 -08:00
|
|
|
};
|
2012-08-20 12:23:37 -07:00
|
|
|
let inner_handler = diagnostic::mk_handler(Some(emitter));
|
2012-02-17 14:15:09 -08:00
|
|
|
let handler = {
|
|
|
|
inner: inner_handler,
|
|
|
|
};
|
|
|
|
let span_handler = diagnostic::mk_span_handler(
|
|
|
|
handler as diagnostic::handler, codemap);
|
|
|
|
|
|
|
|
{
|
|
|
|
emitter: emitter,
|
2012-07-18 10:14:28 -07:00
|
|
|
span_handler: span_handler
|
2012-02-17 14:15:09 -08:00
|
|
|
}
|
2012-01-26 00:35:07 -08:00
|
|
|
}
|
|
|
|
|
2012-01-18 15:48:09 -08:00
|
|
|
#[test]
|
|
|
|
fn should_prune_unconfigured_items() {
|
2012-07-13 22:57:48 -07:00
|
|
|
let source = ~"#[cfg(shut_up_and_leave_me_alone)]fn a() { }";
|
2012-06-30 16:19:07 -07:00
|
|
|
do from_str(source) |srv| {
|
|
|
|
do exec(srv) |ctxt| {
|
2012-02-20 21:08:19 -08:00
|
|
|
assert vec::is_empty(ctxt.ast.node.module.items);
|
|
|
|
}
|
2012-01-18 15:48:09 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-26 00:35:07 -08:00
|
|
|
#[test]
|
|
|
|
fn srv_should_build_ast_map() {
|
2012-07-13 22:57:48 -07:00
|
|
|
let source = ~"fn a() { }";
|
2012-06-30 16:19:07 -07:00
|
|
|
do from_str(source) |srv| {
|
|
|
|
do exec(srv) |ctxt| {
|
2012-02-20 21:08:19 -08:00
|
|
|
assert ctxt.ast_map.size() != 0u
|
|
|
|
};
|
|
|
|
}
|
2012-01-26 00:35:07 -08:00
|
|
|
}
|
|
|
|
|
2012-02-17 17:34:44 -08:00
|
|
|
#[test]
|
|
|
|
fn should_ignore_external_import_paths_that_dont_exist() {
|
2012-09-07 18:08:21 -07:00
|
|
|
let source = ~"use forble; use forble::bippy;";
|
2012-06-30 16:19:07 -07:00
|
|
|
from_str(source, |_srv| { } )
|
2012-02-17 17:34:44 -08:00
|
|
|
}
|
|
|
|
|
2012-01-26 00:35:07 -08:00
|
|
|
#[test]
|
|
|
|
fn srv_should_return_request_result() {
|
2012-07-13 22:57:48 -07:00
|
|
|
let source = ~"fn a() { }";
|
2012-06-30 16:19:07 -07:00
|
|
|
do from_str(source) |srv| {
|
|
|
|
let result = exec(srv, |_ctxt| 1000 );
|
2012-02-20 21:08:19 -08:00
|
|
|
assert result == 1000;
|
|
|
|
}
|
2012-01-26 00:35:07 -08:00
|
|
|
}
|