Commit c897ac04 authored by bors's avatar bors

Auto merge of #24177 - alexcrichton:rustdoc, r=aturon

This commit series starts out with more official test harness support for rustdoc tests, and then each commit afterwards adds a test (where appropriate). Each commit should also test and finish independently of all others (they're all pretty separable).

I've uploaded a [copy of the documentation](http://people.mozilla.org/~acrichton/doc/std/) generated after all these commits were applied, and a double check on issues being closed would be greatly appreciated! I'll also browse the docs a bit and make sure nothing regressed too horribly.
parents 9539627a 445faca8
......@@ -1128,6 +1128,7 @@ do
make_dir $h/test/debuginfo-gdb
make_dir $h/test/debuginfo-lldb
make_dir $h/test/codegen
make_dir $h/test/rustdoc
done
# Configure submodules
......
......@@ -118,42 +118,13 @@ ONLY_RLIB_collections := 1
ONLY_RLIB_unicode := 1
ONLY_RLIB_rustc_bitflags := 1
# Documented-by-default crates
DOC_CRATES := std alloc collections core libc unicode
################################################################################
# You should not need to edit below this line
################################################################################
# On channels where the only usable crate is std, only build documentation for
# std. This keeps distributions small and doesn't clutter up the API docs with
# confusing internal details from the crates behind the facade.
#
# (Disabled while cmr figures out how to change rustdoc to make reexports work
# slightly nicer. Otherwise, all cross-crate links to Vec will go to
# libcollections, breaking them, and [src] links for anything reexported will
# not work.)
#ifeq ($(CFG_RELEASE_CHANNEL),stable)
#DOC_CRATES := std
#else
#ifeq ($(CFG_RELEASE_CHANNEL),beta)
#DOC_CRATES := std
#else
DOC_CRATES := $(filter-out rustc, \
$(filter-out rustc_trans, \
$(filter-out rustc_typeck, \
$(filter-out rustc_borrowck, \
$(filter-out rustc_resolve, \
$(filter-out rustc_driver, \
$(filter-out rustc_privacy, \
$(filter-out rustc_lint, \
$(filter-out log, \
$(filter-out getopts, \
$(filter-out syntax, $(CRATES))))))))))))
#endif
#endif
COMPILER_DOC_CRATES := rustc rustc_trans rustc_borrowck rustc_resolve \
rustc_typeck rustc_driver syntax rustc_privacy \
rustc_lint
# This macro creates some simple definitions for each crate being built, just
# some munging of all of the parameters above.
#
......
......@@ -250,18 +250,20 @@ endif
doc/$(1)/:
$$(Q)mkdir -p $$@
$(2) += doc/$(1)/index.html
doc/$(1)/index.html: CFG_COMPILER_HOST_TRIPLE = $(CFG_TARGET)
doc/$(1)/index.html: $$(LIB_DOC_DEP_$(1)) doc/$(1)/
@$$(call E, rustdoc: $$@)
$$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(CFG_BUILD)) \
$$(RUSTDOC) --cfg dox --cfg stage2 $$<
$$(RUSTDOC) --cfg dox --cfg stage2 $$(RUSTFLAGS_$(1)) $$<
endef
$(foreach crate,$(DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),DOC_TARGETS)))
$(foreach crate,$(CRATES),$(eval $(call DEF_LIB_DOC,$(crate))))
COMPILER_DOC_TARGETS := $(CRATES:%=doc/%/index.html)
ifdef CFG_COMPILER_DOCS
$(foreach crate,$(COMPILER_DOC_CRATES),$(eval $(call DEF_LIB_DOC,$(crate),COMPILER_DOC_TARGETS)))
DOC_TARGETS += $(COMPILER_DOC_TARGETS)
else
DOC_TARGETS += $(DOC_CRATES:%=doc/%/index.html)
endif
ifdef CFG_DISABLE_DOCS
......
......@@ -22,9 +22,11 @@ $(eval $(call RUST_CRATE,coretest))
DEPS_collectionstest :=
$(eval $(call RUST_CRATE,collectionstest))
TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) collectionstest coretest
TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) \
collectionstest coretest
TEST_DOC_CRATES = $(DOC_CRATES)
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve rustc_trans rustc_lint,\
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve \
rustc_trans rustc_lint,\
$(HOST_CRATES))
TEST_CRATES = $(TEST_TARGET_CRATES) $(TEST_HOST_CRATES)
......@@ -304,6 +306,7 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-cfail-full-exec \
check-stage$(1)-T-$(2)-H-$(3)-rmake-exec \
check-stage$(1)-T-$(2)-H-$(3)-rustdocck-exec \
check-stage$(1)-T-$(2)-H-$(3)-crates-exec \
check-stage$(1)-T-$(2)-H-$(3)-doc-crates-exec \
check-stage$(1)-T-$(2)-H-$(3)-bench-exec \
......@@ -471,6 +474,7 @@ DEBUGINFO_GDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
DEBUGINFO_LLDB_RS := $(wildcard $(S)src/test/debuginfo/*.rs)
CODEGEN_RS := $(wildcard $(S)src/test/codegen/*.rs)
CODEGEN_CC := $(wildcard $(S)src/test/codegen/*.cc)
RUSTDOCCK_RS := $(wildcard $(S)src/test/rustdoc/*.rs)
# perf tests are the same as bench tests only they run under
# a performance monitor.
......@@ -489,6 +493,7 @@ PRETTY_TESTS := $(PRETTY_RS)
DEBUGINFO_GDB_TESTS := $(DEBUGINFO_GDB_RS)
DEBUGINFO_LLDB_TESTS := $(DEBUGINFO_LLDB_RS)
CODEGEN_TESTS := $(CODEGEN_RS) $(CODEGEN_CC)
RUSTDOCCK_TESTS := $(RUSTDOCCK_RS)
CTEST_SRC_BASE_rpass = run-pass
CTEST_BUILD_BASE_rpass = run-pass
......@@ -550,6 +555,11 @@ CTEST_BUILD_BASE_codegen = codegen
CTEST_MODE_codegen = codegen
CTEST_RUNTOOL_codegen = $(CTEST_RUNTOOL)
CTEST_SRC_BASE_rustdocck = rustdoc
CTEST_BUILD_BASE_rustdocck = rustdoc
CTEST_MODE_rustdocck = rustdoc
CTEST_RUNTOOL_rustdocck = $(CTEST_RUNTOOL)
# CTEST_DISABLE_$(TEST_GROUP), if set, will cause the test group to be
# disabled and the associated message to be printed as a warning
# during attempts to run those tests.
......@@ -618,12 +628,14 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \
--compile-lib-path $$(HLIB$(1)_H_$(3)) \
--run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \
--rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
--rustdoc-path $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
--clang-path $(if $(CFG_CLANG),$(CFG_CLANG),clang) \
--llvm-bin-path $(CFG_LLVM_INST_DIR_$(CFG_BUILD))/bin \
--aux-base $$(S)src/test/auxiliary/ \
--stage-id stage$(1)-$(2) \
--target $(2) \
--host $(3) \
--python $$(CFG_PYTHON) \
--gdb-version="$(CFG_GDB_VERSION)" \
--lldb-version="$(CFG_LLDB_VERSION)" \
--android-cross-path=$(CFG_ANDROID_CROSS_PATH) \
......@@ -660,6 +672,9 @@ CTEST_DEPS_debuginfo-lldb_$(1)-T-$(2)-H-$(3) = $$(DEBUGINFO_LLDB_TESTS) \
$(S)src/etc/lldb_batchmode.py \
$(S)src/etc/lldb_rust_formatters.py
CTEST_DEPS_codegen_$(1)-T-$(2)-H-$(3) = $$(CODEGEN_TESTS)
CTEST_DEPS_rustdocck_$(1)-T-$(2)-H-$(3) = $$(RUSTDOCCK_TESTS) \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
$(S)src/etc/htmldocck.py
endef
......@@ -722,7 +737,8 @@ endif
endef
CTEST_NAMES = rpass rpass-valgrind rpass-full cfail-full rfail cfail pfail bench perf debuginfo-gdb debuginfo-lldb codegen
CTEST_NAMES = rpass rpass-valgrind rpass-full cfail-full rfail cfail pfail \
bench perf debuginfo-gdb debuginfo-lldb codegen rustdocck
$(foreach host,$(CFG_HOST), \
$(eval $(foreach target,$(CFG_TARGET), \
......@@ -890,6 +906,7 @@ TEST_GROUPS = \
bench \
perf \
rmake \
rustdocck \
debuginfo-gdb \
debuginfo-lldb \
codegen \
......
......@@ -23,7 +23,8 @@ pub enum Mode {
Pretty,
DebugInfoGdb,
DebugInfoLldb,
Codegen
Codegen,
Rustdoc,
}
impl FromStr for Mode {
......@@ -39,6 +40,7 @@ impl FromStr for Mode {
"debuginfo-lldb" => Ok(DebugInfoLldb),
"debuginfo-gdb" => Ok(DebugInfoGdb),
"codegen" => Ok(Codegen),
"rustdoc" => Ok(Rustdoc),
_ => Err(()),
}
}
......@@ -56,6 +58,7 @@ impl fmt::Display for Mode {
DebugInfoGdb => "debuginfo-gdb",
DebugInfoLldb => "debuginfo-lldb",
Codegen => "codegen",
Rustdoc => "rustdoc",
}, f)
}
}
......@@ -71,6 +74,12 @@ pub struct Config {
// The rustc executable
pub rustc_path: PathBuf,
// The rustdoc executable
pub rustdoc_path: PathBuf,
// The python executable
pub python: String,
// The clang executable
pub clang_path: Option<PathBuf>,
......
......@@ -60,6 +60,8 @@ pub fn parse_config(args: Vec<String> ) -> Config {
vec!(reqopt("", "compile-lib-path", "path to host shared libraries", "PATH"),
reqopt("", "run-lib-path", "path to target shared libraries", "PATH"),
reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"),
reqopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH"),
reqopt("", "python", "path to python to use for doc tests", "PATH"),
optopt("", "clang-path", "path to executable for codegen tests", "PATH"),
optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM"),
optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind"),
......@@ -128,6 +130,8 @@ pub fn parse_config(args: Vec<String> ) -> Config {
compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
run_lib_path: matches.opt_str("run-lib-path").unwrap(),
rustc_path: opt_path(matches, "rustc-path"),
rustdoc_path: opt_path(matches, "rustdoc-path"),
python: matches.opt_str("python").unwrap(),
clang_path: matches.opt_str("clang-path").map(|s| PathBuf::from(&s)),
valgrind_path: matches.opt_str("valgrind-path"),
force_valgrind: matches.opt_present("force-valgrind"),
......@@ -168,6 +172,7 @@ pub fn log_config(config: &Config) {
logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path));
logv(c, format!("run_lib_path: {:?}", config.run_lib_path));
logv(c, format!("rustc_path: {:?}", config.rustc_path.display()));
logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path.display()));
logv(c, format!("src_base: {:?}", config.src_base.display()));
logv(c, format!("build_base: {:?}", config.build_base.display()));
logv(c, format!("stage_id: {}", config.stage_id));
......
......@@ -12,7 +12,7 @@ use self::TargetLocation::*;
use common::Config;
use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
use common::{Codegen, DebugInfoLldb, DebugInfoGdb};
use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc};
use errors;
use header::TestProps;
use header;
......@@ -57,15 +57,16 @@ pub fn run_metrics(config: Config, testfile: &Path, mm: &mut MetricMap) {
let props = header::load_props(&testfile);
debug!("loaded props");
match config.mode {
CompileFail => run_cfail_test(&config, &props, &testfile),
ParseFail => run_cfail_test(&config, &props, &testfile),
RunFail => run_rfail_test(&config, &props, &testfile),
RunPass => run_rpass_test(&config, &props, &testfile),
RunPassValgrind => run_valgrind_test(&config, &props, &testfile),
Pretty => run_pretty_test(&config, &props, &testfile),
DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testfile),
DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile),
Codegen => run_codegen_test(&config, &props, &testfile, mm),
CompileFail => run_cfail_test(&config, &props, &testfile),
ParseFail => run_cfail_test(&config, &props, &testfile),
RunFail => run_rfail_test(&config, &props, &testfile),
RunPass => run_rpass_test(&config, &props, &testfile),
RunPassValgrind => run_valgrind_test(&config, &props, &testfile),
Pretty => run_pretty_test(&config, &props, &testfile),
DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testfile),
DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile),
Codegen => run_codegen_test(&config, &props, &testfile, mm),
Rustdoc => run_rustdoc_test(&config, &props, &testfile),
}
}
......@@ -725,32 +726,37 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
-> ProcRes {
// Prepare the lldb_batchmode which executes the debugger script
let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
cmd2procres(config,
test_executable,
Command::new(&config.python)
.arg(&lldb_script_path)
.arg(test_executable)
.arg(debugger_script)
.env("PYTHONPATH",
config.lldb_python_dir.as_ref().unwrap()))
}
}
let mut cmd = Command::new("python");
cmd.arg(&lldb_script_path)
.arg(test_executable)
.arg(debugger_script)
.env("PYTHONPATH", config.lldb_python_dir.as_ref().unwrap());
let (status, out, err) = match cmd.output() {
Ok(Output { status, stdout, stderr }) => {
(status,
String::from_utf8(stdout).unwrap(),
String::from_utf8(stderr).unwrap())
},
Err(e) => {
fatal(&format!("Failed to setup Python process for \
LLDB script: {}", e))
}
};
fn cmd2procres(config: &Config, test_executable: &Path, cmd: &mut Command)
-> ProcRes {
let (status, out, err) = match cmd.output() {
Ok(Output { status, stdout, stderr }) => {
(status,
String::from_utf8(stdout).unwrap(),
String::from_utf8(stderr).unwrap())
},
Err(e) => {
fatal(&format!("Failed to setup Python process for \
LLDB script: {}", e))
}
};
dump_output(config, test_executable, &out, &err);
return ProcRes {
status: Status::Normal(status),
stdout: out,
stderr: err,
cmdline: format!("{:?}", cmd)
};
dump_output(config, test_executable, &out, &err);
ProcRes {
status: Status::Normal(status),
stdout: out,
stderr: err,
cmdline: format!("{:?}", cmd)
}
}
......@@ -1157,6 +1163,26 @@ fn compile_test_(config: &Config, props: &TestProps,
compose_and_run_compiler(config, props, testfile, args, None)
}
fn document(config: &Config, props: &TestProps,
testfile: &Path, extra_args: &[String]) -> (ProcRes, PathBuf) {
let aux_dir = aux_output_dir_name(config, testfile);
let out_dir = output_base_name(config, testfile);
let _ = fs::remove_dir_all(&out_dir);
ensure_dir(&out_dir);
let mut args = vec!["-L".to_string(),
aux_dir.to_str().unwrap().to_string(),
"-o".to_string(),
out_dir.to_str().unwrap().to_string(),
testfile.to_str().unwrap().to_string()];
args.extend(extra_args.iter().cloned());
args.extend(split_maybe_args(&props.compile_flags).into_iter());
let args = ProcArgs {
prog: config.rustdoc_path.to_str().unwrap().to_string(),
args: args,
};
(compose_and_run_compiler(config, props, testfile, args, None), out_dir)
}
fn exec_compiled_test(config: &Config, props: &TestProps,
testfile: &Path) -> ProcRes {
......@@ -1181,20 +1207,17 @@ fn exec_compiled_test(config: &Config, props: &TestProps,
}
}
fn compose_and_run_compiler(
config: &Config,
props: &TestProps,
testfile: &Path,
args: ProcArgs,
input: Option<String>) -> ProcRes {
fn compose_and_run_compiler(config: &Config, props: &TestProps,
testfile: &Path, args: ProcArgs,
input: Option<String>) -> ProcRes {
if !props.aux_builds.is_empty() {
ensure_dir(&aux_output_dir_name(config, testfile));
}
let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths
let extra_link_args = vec!("-L".to_string(), aux_dir.to_str().unwrap().to_string());
let extra_link_args = vec!["-L".to_string(),
aux_dir.to_str().unwrap().to_string()];
for rel_ab in &props.aux_builds {
let abs_ab = config.aux_base.join(rel_ab);
......@@ -1330,8 +1353,8 @@ fn make_exe_name(config: &Config, testfile: &Path) -> PathBuf {
f
}
fn make_run_args(config: &Config, props: &TestProps, testfile: &Path) ->
ProcArgs {
fn make_run_args(config: &Config, props: &TestProps, testfile: &Path)
-> ProcArgs {
// If we've got another tool to run under (valgrind),
// then split apart its command
let mut args = split_maybe_args(&config.runtool);
......@@ -1797,3 +1820,21 @@ fn charset() -> &'static str {
"UTF-8"
}
}
fn run_rustdoc_test(config: &Config, props: &TestProps, testfile: &Path) {
let (proc_res, out_dir) = document(config, props, testfile, &[]);
if !proc_res.status.success() {
fatal_proc_rec("rustdoc failed!", &proc_res);
}
let root = find_rust_src_root(config).unwrap();
let res = cmd2procres(config,
testfile,
Command::new(&config.python)
.arg(root.join("src/etc/htmldocck.py"))
.arg(out_dir)
.arg(testfile));
if !res.status.success() {
fatal_proc_rec("htmldocck failed!", &res);
}
}
......@@ -89,7 +89,9 @@ This line does all of the work in our little program. There are a number of
details that are important here. The first is that it's indented with four
spaces, not tabs. Please configure your editor of choice to insert four spaces
with the tab key. We provide some [sample configurations for various
editors](https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md).
editors][configs].
[configs]: https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md
The second point is the `println!()` part. This is calling a Rust *macro*,
which is how metaprogramming is done in Rust. If it were a function instead, it
......
......@@ -186,7 +186,8 @@ def concat_multi_lines(f):
firstlineno = firstlineno or lineno
if line.endswith('\\'):
lastline = line[:-1]
if lastline is None:
lastline = line[:-1]
catenated += line[:-1]
else:
yield firstlineno, catenated + line
......
......@@ -139,6 +139,7 @@ pub fn from_digit(num: u32, radix: u32) -> Option<char> {
// NB: the stabilization and documentation for this trait is in
// unicode/char.rs, not here
#[allow(missing_docs)] // docs in libunicode/u_char.rs
#[doc(hidden)]
pub trait CharExt {
fn is_digit(self, radix: u32) -> bool;
fn to_digit(self, radix: u32) -> Option<u32>;
......
......@@ -229,7 +229,6 @@ macro_rules! writeln {
/// Iterators:
///
/// ```
/// # #![feature(core)]
/// fn divide_by_three(x: u32) -> u32 { // one of the poorest implementations of x/3
/// for i in 0.. {
/// if 3*i < i { panic!("u32 overflow"); }
......
......@@ -2490,6 +2490,7 @@ pub enum FpCategory {
// `unused_self`. Removing it requires #8888 to be fixed.
#[unstable(feature = "core",
reason = "distribution of methods between core/std is unclear")]
#[doc(hidden)]
pub trait Float
: Copy + Clone
+ NumCast
......
......@@ -89,6 +89,7 @@
//! of unsafe pointers in Rust.
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "pointer")]
use mem;
use clone::Clone;
......
......@@ -63,6 +63,7 @@ use raw::Slice as RawSlice;
/// Extension methods for slices.
#[allow(missing_docs)] // docs in libcollections
#[doc(hidden)]
pub trait SliceExt {
type Item;
......
......@@ -1496,6 +1496,7 @@ impl<'a, S: ?Sized> Str for &'a S where S: Str {
/// Methods for string slices
#[allow(missing_docs)]
#[doc(hidden)]
pub trait StrExt {
// NB there are no docs here are they're all located on the StrExt trait in
// libcollections, not here.
......
......@@ -1264,7 +1264,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_paren_sugar(rbml_w, trait_def.paren_sugar);
encode_defaulted(rbml_w, ty::trait_has_default_impl(tcx, def_id));
encode_associated_type_names(rbml_w, &trait_def.associated_type_names);
encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates, tag_item_generics);
encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates,
tag_item_generics);
encode_predicates(rbml_w, ecx, &ty::lookup_super_predicates(tcx, def_id),
tag_item_super_predicates);
encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
......
......@@ -10,6 +10,8 @@
//! Support for inlining external documentation into the current AST.
use std::collections::HashSet;
use syntax::ast;
use syntax::ast_util;
use syntax::attr::AttrMetaMethods;
......@@ -150,18 +152,21 @@ pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt,
let def = ty::lookup_trait_def(tcx, did);
let trait_items = ty::trait_items(tcx, did).clean(cx);
let predicates = ty::lookup_predicates(tcx, did);
let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx);
let generics = filter_non_trait_generics(did, generics);
let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
clean::Trait {
unsafety: def.unsafety,
generics: (&def.generics, &predicates, subst::TypeSpace).clean(cx),
generics: generics,
items: trait_items,
bounds: vec![], // supertraits can be found in the list of predicates
bounds: supertrait_bounds,
}
}
fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Function {
let t = ty::lookup_item_type(tcx, did);
let (decl, style) = match t.ty.sty {
ty::ty_bare_fn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety),
let (decl, style, abi) = match t.ty.sty {
ty::ty_bare_fn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
_ => panic!("bad function"),
};
let predicates = ty::lookup_predicates(tcx, did);
......@@ -169,6 +174,7 @@ fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) ->
decl: decl,
generics: (&t.generics, &predicates, subst::FnSpace).clean(cx),
unsafety: style,
abi: abi,
}
}
......@@ -331,9 +337,10 @@ fn build_impl(cx: &DocContext,
let did = assoc_ty.def_id;
let type_scheme = ty::lookup_item_type(tcx, did);
let predicates = ty::lookup_predicates(tcx, did);
// Not sure the choice of ParamSpace actually matters here, because an
// associated type won't have generics on the LHS
let typedef = (type_scheme, predicates, subst::ParamSpace::TypeSpace).clean(cx);
// Not sure the choice of ParamSpace actually matters here,
// because an associated type won't have generics on the LHS
let typedef = (type_scheme, predicates,
subst::ParamSpace::TypeSpace).clean(cx);
Some(clean::Item {
name: Some(assoc_ty.name.clean(cx)),
inner: clean::TypedefItem(typedef),
......@@ -395,16 +402,19 @@ fn build_module(cx: &DocContext, tcx: &ty::ctxt,
is_crate: false,
};
// FIXME: this doesn't handle reexports inside the module itself.
// Should they be handled?
fn fill_in(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId,
items: &mut Vec<clean::Item>) {
// If we're reexporting a reexport it may actually reexport something in
// two namespaces, so the target may be listed twice. Make sure we only
// visit each node at most once.
let mut visited = HashSet::new();
csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, vis| {
match def {
decoder::DlDef(def::DefForeignMod(did)) => {
fill_in(cx, tcx, did, items);
}
decoder::DlDef(def) if vis == ast::Public => {
if !visited.insert(def) { return }
match try_inline_def(cx, tcx, def) {
Some(i) => items.extend(i.into_iter()),
None => {}
......@@ -446,3 +456,48 @@ fn build_static(cx: &DocContext, tcx: &ty::ctxt,
expr: "\n\n\n".to_string(), // trigger the "[definition]" links
}
}
/// A trait's generics clause actually contains all of the predicates for all of
/// its associated types as well. We specifically move these clauses to the
/// associated types instead when displaying, so when we're genering the
/// generics for the trait itself we need to be sure to remove them.
///
/// The inverse of this filtering logic can be found in the `Clean`
/// implementation for `AssociatedType`
fn filter_non_trait_generics(trait_did: ast::DefId, mut g: clean::Generics)
-> clean::Generics {
g.where_predicates.retain(|pred| {
match *pred {
clean::WherePredicate::BoundPredicate {