Skip to content

Commit 8ab2c20

Browse files
committed
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.
1 parent a264f5b commit 8ab2c20

File tree

4 files changed

+87
-27
lines changed

4 files changed

+87
-27
lines changed

src/etc/htmldocck.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,9 @@ def check_tree_text(tree, path, pat, regexp):
342342
return ret
343343

344344

345-
def check_tree_count(tree, path, count):
345+
def get_tree_count(tree, path):
346346
path = normalize_xpath(path)
347-
return len(tree.findall(path)) == count
347+
return len(tree.findall(path))
348348

349349
def stderr(*args):
350350
print(*args, file=sys.stderr)
@@ -393,7 +393,10 @@ def check_command(c, cache):
393393

394394
elif c.cmd == 'count': # count test
395395
if len(c.args) == 3: # @count <path> <pat> <count> = count test
396-
ret = check_tree_count(cache.get_tree(c.args[0]), c.args[1], int(c.args[2]))
396+
expected = int(c.args[2])
397+
found = get_tree_count(cache.get_tree(c.args[0]), c.args[1])
398+
cerr = "Expected {} occurrences but found {}".format(expected, found)
399+
ret = expected == found
397400
else:
398401
raise InvalidCheck('Invalid number of @{} arguments'.format(c.cmd))
399402
elif c.cmd == 'valid-html':

src/librustdoc/html/render.rs

+38-24
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ pub struct Cache {
258258
parent_stack: Vec<DefId>,
259259
parent_is_trait_impl: bool,
260260
search_index: Vec<IndexItem>,
261+
seen_modules: HashSet<DefId>,
262+
seen_mod: bool,
261263
stripped_mod: bool,
262264
deref_trait_did: Option<DefId>,
263265

@@ -520,6 +522,8 @@ pub fn run(mut krate: clean::Crate,
520522
parent_is_trait_impl: false,
521523
extern_locations: HashMap::new(),
522524
primitive_locations: HashMap::new(),
525+
seen_modules: HashSet::new(),
526+
seen_mod: false,
523527
stripped_mod: false,
524528
access_levels: krate.access_levels.clone(),
525529
orphan_methods: Vec::new(),
@@ -976,13 +980,20 @@ impl DocFolder for Cache {
976980
// we don't want it or its children in the search index.
977981
let orig_stripped_mod = match item.inner {
978982
clean::StrippedItem(box clean::ModuleItem(..)) => {
979-
let prev = self.stripped_mod;
980-
self.stripped_mod = true;
981-
prev
983+
mem::replace(&mut self.stripped_mod, true)
982984
}
983985
_ => self.stripped_mod,
984986
};
985987

988+
// Inlining can cause us to visit the same item multiple times.
989+
// (i.e. relevant for gathering impls and implementors)
990+
let orig_seen_mod = if item.is_mod() {
991+
let seen_this = self.seen_mod || !self.seen_modules.insert(item.def_id);
992+
mem::replace(&mut self.seen_mod, seen_this)
993+
} else {
994+
self.seen_mod
995+
};
996+
986997
// Register any generics to their corresponding string. This is used
987998
// when pretty-printing types
988999
match item.inner {
@@ -998,20 +1009,22 @@ impl DocFolder for Cache {
9981009
_ => {}
9991010
}
10001011

1001-
// Propagate a trait methods' documentation to all implementors of the
1002-
// trait
1003-
if let clean::TraitItem(ref t) = item.inner {
1004-
self.traits.insert(item.def_id, t.clone());
1005-
}
1012+
if !self.seen_mod {
1013+
// Propagate a trait methods' documentation to all implementors of the
1014+
// trait
1015+
if let clean::TraitItem(ref t) = item.inner {
1016+
self.traits.insert(item.def_id, t.clone());
1017+
}
10061018

1007-
// Collect all the implementors of traits.
1008-
if let clean::ImplItem(ref i) = item.inner {
1009-
if let Some(did) = i.trait_.def_id() {
1010-
self.implementors.entry(did).or_insert(vec![]).push(Implementor {
1011-
def_id: item.def_id,
1012-
stability: item.stability.clone(),
1013-
impl_: i.clone(),
1014-
});
1019+
// Collect all the implementors of traits.
1020+
if let clean::ImplItem(ref i) = item.inner {
1021+
if let Some(did) = i.trait_.def_id() {
1022+
self.implementors.entry(did).or_insert(vec![]).push(Implementor {
1023+
def_id: item.def_id,
1024+
stability: item.stability.clone(),
1025+
impl_: i.clone(),
1026+
});
1027+
}
10151028
}
10161029
}
10171030

@@ -1183,7 +1196,6 @@ impl DocFolder for Cache {
11831196
} => {
11841197
Some(did)
11851198
}
1186-
11871199
ref t => {
11881200
t.primitive_type().and_then(|t| {
11891201
self.primitive_locations.get(&t).map(|n| {
@@ -1193,13 +1205,14 @@ impl DocFolder for Cache {
11931205
})
11941206
}
11951207
};
1196-
1197-
if let Some(did) = did {
1198-
self.impls.entry(did).or_insert(vec![]).push(Impl {
1199-
impl_: i,
1200-
dox: attrs.value("doc").map(|s|s.to_owned()),
1201-
stability: item.stability.clone(),
1202-
});
1208+
if !self.seen_mod {
1209+
if let Some(did) = did {
1210+
self.impls.entry(did).or_insert(vec![]).push(Impl {
1211+
impl_: i,
1212+
dox: attrs.value("doc").map(|s|s.to_owned()),
1213+
stability: item.stability.clone(),
1214+
});
1215+
}
12031216
}
12041217
None
12051218
} else {
@@ -1209,6 +1222,7 @@ impl DocFolder for Cache {
12091222

12101223
if pushed { self.stack.pop().unwrap(); }
12111224
if parent_pushed { self.parent_stack.pop().unwrap(); }
1225+
self.seen_mod = orig_seen_mod;
12121226
self.stripped_mod = orig_stripped_mod;
12131227
self.parent_is_trait_impl = orig_parent_is_trait_impl;
12141228
return ret;
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub struct Foo;
12+
13+
// just so that `Foo` doesn't show up on `Bar`s sidebar
14+
pub mod bar {
15+
pub trait Bar {}
16+
}
17+
18+
impl Foo {
19+
pub fn new() -> Foo { Foo }
20+
}
21+
22+
impl bar::Bar for Foo {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// @has issue_33054/impls/struct.Foo.html
12+
// @has - '//code' 'impl Foo'
13+
// @has - '//code' 'impl Bar for Foo'
14+
// @count - '//*[@class="impl"]' 2
15+
// @has issue_33054/impls/bar/trait.Bar.html
16+
// @has - '//code' 'impl Bar for Foo'
17+
// @count - '//*[@class="struct"]' 1
18+
pub mod impls;
19+
20+
#[doc(inline)]
21+
pub use impls as impls2;

0 commit comments

Comments
 (0)