Only record the same impl once
Due to inlining it is possible to visit the same module multiple times during `<Cache as DocFolder>::fold_crate`, so we keep track of the modules we've already visited.
This commit is contained in:
@@ -342,9 +342,9 @@ def check_tree_text(tree, path, pat, regexp):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def check_tree_count(tree, path, count):
|
def get_tree_count(tree, path):
|
||||||
path = normalize_xpath(path)
|
path = normalize_xpath(path)
|
||||||
return len(tree.findall(path)) == count
|
return len(tree.findall(path))
|
||||||
|
|
||||||
def stderr(*args):
|
def stderr(*args):
|
||||||
print(*args, file=sys.stderr)
|
print(*args, file=sys.stderr)
|
||||||
@@ -393,7 +393,10 @@ def check_command(c, cache):
|
|||||||
|
|
||||||
elif c.cmd == 'count': # count test
|
elif c.cmd == 'count': # count test
|
||||||
if len(c.args) == 3: # @count <path> <pat> <count> = count test
|
if len(c.args) == 3: # @count <path> <pat> <count> = count test
|
||||||
ret = check_tree_count(cache.get_tree(c.args[0]), c.args[1], int(c.args[2]))
|
expected = int(c.args[2])
|
||||||
|
found = get_tree_count(cache.get_tree(c.args[0]), c.args[1])
|
||||||
|
cerr = "Expected {} occurrences but found {}".format(expected, found)
|
||||||
|
ret = expected == found
|
||||||
else:
|
else:
|
||||||
raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
|
raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
|
||||||
elif c.cmd == 'valid-html':
|
elif c.cmd == 'valid-html':
|
||||||
|
|||||||
@@ -258,6 +258,8 @@ pub struct Cache {
|
|||||||
parent_stack: Vec<DefId>,
|
parent_stack: Vec<DefId>,
|
||||||
parent_is_trait_impl: bool,
|
parent_is_trait_impl: bool,
|
||||||
search_index: Vec<IndexItem>,
|
search_index: Vec<IndexItem>,
|
||||||
|
seen_modules: HashSet<DefId>,
|
||||||
|
seen_mod: bool,
|
||||||
stripped_mod: bool,
|
stripped_mod: bool,
|
||||||
deref_trait_did: Option<DefId>,
|
deref_trait_did: Option<DefId>,
|
||||||
|
|
||||||
@@ -520,6 +522,8 @@ pub fn run(mut krate: clean::Crate,
|
|||||||
parent_is_trait_impl: false,
|
parent_is_trait_impl: false,
|
||||||
extern_locations: HashMap::new(),
|
extern_locations: HashMap::new(),
|
||||||
primitive_locations: HashMap::new(),
|
primitive_locations: HashMap::new(),
|
||||||
|
seen_modules: HashSet::new(),
|
||||||
|
seen_mod: false,
|
||||||
stripped_mod: false,
|
stripped_mod: false,
|
||||||
access_levels: krate.access_levels.clone(),
|
access_levels: krate.access_levels.clone(),
|
||||||
orphan_methods: Vec::new(),
|
orphan_methods: Vec::new(),
|
||||||
@@ -976,13 +980,20 @@ impl DocFolder for Cache {
|
|||||||
// we don't want it or its children in the search index.
|
// we don't want it or its children in the search index.
|
||||||
let orig_stripped_mod = match item.inner {
|
let orig_stripped_mod = match item.inner {
|
||||||
clean::StrippedItem(box clean::ModuleItem(..)) => {
|
clean::StrippedItem(box clean::ModuleItem(..)) => {
|
||||||
let prev = self.stripped_mod;
|
mem::replace(&mut self.stripped_mod, true)
|
||||||
self.stripped_mod = true;
|
|
||||||
prev
|
|
||||||
}
|
}
|
||||||
_ => self.stripped_mod,
|
_ => self.stripped_mod,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Inlining can cause us to visit the same item multiple times.
|
||||||
|
// (i.e. relevant for gathering impls and implementors)
|
||||||
|
let orig_seen_mod = if item.is_mod() {
|
||||||
|
let seen_this = self.seen_mod || !self.seen_modules.insert(item.def_id);
|
||||||
|
mem::replace(&mut self.seen_mod, seen_this)
|
||||||
|
} else {
|
||||||
|
self.seen_mod
|
||||||
|
};
|
||||||
|
|
||||||
// Register any generics to their corresponding string. This is used
|
// Register any generics to their corresponding string. This is used
|
||||||
// when pretty-printing types
|
// when pretty-printing types
|
||||||
match item.inner {
|
match item.inner {
|
||||||
@@ -998,6 +1009,7 @@ impl DocFolder for Cache {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !self.seen_mod {
|
||||||
// Propagate a trait methods' documentation to all implementors of the
|
// Propagate a trait methods' documentation to all implementors of the
|
||||||
// trait
|
// trait
|
||||||
if let clean::TraitItem(ref t) = item.inner {
|
if let clean::TraitItem(ref t) = item.inner {
|
||||||
@@ -1014,6 +1026,7 @@ impl DocFolder for Cache {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Index this method for searching later on
|
// Index this method for searching later on
|
||||||
if let Some(ref s) = item.name {
|
if let Some(ref s) = item.name {
|
||||||
@@ -1183,7 +1196,6 @@ impl DocFolder for Cache {
|
|||||||
} => {
|
} => {
|
||||||
Some(did)
|
Some(did)
|
||||||
}
|
}
|
||||||
|
|
||||||
ref t => {
|
ref t => {
|
||||||
t.primitive_type().and_then(|t| {
|
t.primitive_type().and_then(|t| {
|
||||||
self.primitive_locations.get(&t).map(|n| {
|
self.primitive_locations.get(&t).map(|n| {
|
||||||
@@ -1193,7 +1205,7 @@ impl DocFolder for Cache {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if !self.seen_mod {
|
||||||
if let Some(did) = did {
|
if let Some(did) = did {
|
||||||
self.impls.entry(did).or_insert(vec![]).push(Impl {
|
self.impls.entry(did).or_insert(vec![]).push(Impl {
|
||||||
impl_: i,
|
impl_: i,
|
||||||
@@ -1201,6 +1213,7 @@ impl DocFolder for Cache {
|
|||||||
stability: item.stability.clone(),
|
stability: item.stability.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(item)
|
Some(item)
|
||||||
@@ -1209,6 +1222,7 @@ impl DocFolder for Cache {
|
|||||||
|
|
||||||
if pushed { self.stack.pop().unwrap(); }
|
if pushed { self.stack.pop().unwrap(); }
|
||||||
if parent_pushed { self.parent_stack.pop().unwrap(); }
|
if parent_pushed { self.parent_stack.pop().unwrap(); }
|
||||||
|
self.seen_mod = orig_seen_mod;
|
||||||
self.stripped_mod = orig_stripped_mod;
|
self.stripped_mod = orig_stripped_mod;
|
||||||
self.parent_is_trait_impl = orig_parent_is_trait_impl;
|
self.parent_is_trait_impl = orig_parent_is_trait_impl;
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
22
src/test/rustdoc/duplicate_impls/impls.rs
Normal file
22
src/test/rustdoc/duplicate_impls/impls.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
pub struct Foo;
|
||||||
|
|
||||||
|
// just so that `Foo` doesn't show up on `Bar`s sidebar
|
||||||
|
pub mod bar {
|
||||||
|
pub trait Bar {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
pub fn new() -> Foo { Foo }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl bar::Bar for Foo {}
|
||||||
21
src/test/rustdoc/duplicate_impls/issue-33054.rs
Normal file
21
src/test/rustdoc/duplicate_impls/issue-33054.rs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// @has issue_33054/impls/struct.Foo.html
|
||||||
|
// @has - '//code' 'impl Foo'
|
||||||
|
// @has - '//code' 'impl Bar for Foo'
|
||||||
|
// @count - '//*[@class="impl"]' 2
|
||||||
|
// @has issue_33054/impls/bar/trait.Bar.html
|
||||||
|
// @has - '//code' 'impl Bar for Foo'
|
||||||
|
// @count - '//*[@class="struct"]' 1
|
||||||
|
pub mod impls;
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use impls as impls2;
|
||||||
Reference in New Issue
Block a user