6534: Fix attachment of inner doc comments r=matklad a=matklad

bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2020-11-12 11:09:44 +00:00 committed by GitHub
commit 99fa139bea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 47 deletions

View file

@ -115,7 +115,22 @@ fn test_doc_comment_none() {
} }
#[test] #[test]
fn test_doc_comment_of_items() { fn test_outer_doc_comment_of_items() {
let file = SourceFile::parse(
r#"
/// doc
// non-doc
mod foo {}
"#,
)
.ok()
.unwrap();
let module = file.syntax().descendants().find_map(Module::cast).unwrap();
assert_eq!("doc", module.doc_comment_text().unwrap());
}
#[test]
fn test_inner_doc_comment_of_items() {
let file = SourceFile::parse( let file = SourceFile::parse(
r#" r#"
//! doc //! doc
@ -126,7 +141,7 @@ fn test_doc_comment_of_items() {
.ok() .ok()
.unwrap(); .unwrap();
let module = file.syntax().descendants().find_map(Module::cast).unwrap(); let module = file.syntax().descendants().find_map(Module::cast).unwrap();
assert_eq!("doc", module.doc_comment_text().unwrap()); assert!(module.doc_comment_text().is_none());
} }
#[test] #[test]

View file

@ -14,16 +14,15 @@ use crate::{
impl ast::Comment { impl ast::Comment {
pub fn kind(&self) -> CommentKind { pub fn kind(&self) -> CommentKind {
kind_by_prefix(self.text()) CommentKind::from_text(self.text())
} }
pub fn prefix(&self) -> &'static str { pub fn prefix(&self) -> &'static str {
for (prefix, k) in COMMENT_PREFIX_TO_KIND.iter() { let &(prefix, _kind) = CommentKind::BY_PREFIX
if *k == self.kind() && self.text().starts_with(prefix) { .iter()
return prefix; .find(|&(prefix, kind)| self.kind() == *kind && self.text().starts_with(prefix))
} .unwrap();
} prefix
unreachable!()
} }
} }
@ -55,29 +54,25 @@ pub enum CommentPlacement {
Outer, Outer,
} }
const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = { impl CommentKind {
use {CommentPlacement::*, CommentShape::*}; const BY_PREFIX: [(&'static str, CommentKind); 8] = [
&[ ("/**/", CommentKind { shape: CommentShape::Block, doc: None }),
("////", CommentKind { shape: Line, doc: None }), ("////", CommentKind { shape: CommentShape::Line, doc: None }),
("///", CommentKind { shape: Line, doc: Some(Outer) }), ("///", CommentKind { shape: CommentShape::Line, doc: Some(CommentPlacement::Outer) }),
("//!", CommentKind { shape: Line, doc: Some(Inner) }), ("//!", CommentKind { shape: CommentShape::Line, doc: Some(CommentPlacement::Inner) }),
("/**", CommentKind { shape: Block, doc: Some(Outer) }), ("/**", CommentKind { shape: CommentShape::Block, doc: Some(CommentPlacement::Outer) }),
("/*!", CommentKind { shape: Block, doc: Some(Inner) }), ("/*!", CommentKind { shape: CommentShape::Block, doc: Some(CommentPlacement::Inner) }),
("//", CommentKind { shape: Line, doc: None }), ("//", CommentKind { shape: CommentShape::Line, doc: None }),
("/*", CommentKind { shape: Block, doc: None }), ("/*", CommentKind { shape: CommentShape::Block, doc: None }),
] ];
};
fn kind_by_prefix(text: &str) -> CommentKind { pub(crate) fn from_text(text: &str) -> CommentKind {
if text == "/**/" { let &(_prefix, kind) = CommentKind::BY_PREFIX
return CommentKind { shape: CommentShape::Block, doc: None }; .iter()
.find(|&(prefix, _kind)| text.starts_with(prefix))
.unwrap();
kind
} }
for (prefix, kind) in COMMENT_PREFIX_TO_KIND.iter() {
if text.starts_with(prefix) {
return *kind;
}
}
panic!("bad comment text: {:?}", text)
} }
impl ast::Whitespace { impl ast::Whitespace {

View file

@ -5,6 +5,7 @@ use std::mem;
use parser::{ParseError, TreeSink}; use parser::{ParseError, TreeSink};
use crate::{ use crate::{
ast,
parsing::Token, parsing::Token,
syntax_node::GreenNode, syntax_node::GreenNode,
SmolStr, SyntaxError, SmolStr, SyntaxError,
@ -153,24 +154,22 @@ fn n_attached_trivias<'a>(
while let Some((i, (kind, text))) = trivias.next() { while let Some((i, (kind, text))) = trivias.next() {
match kind { match kind {
WHITESPACE => { WHITESPACE if text.contains("\n\n") => {
if text.contains("\n\n") { // we check whether the next token is a doc-comment
// we check whether the next token is a doc-comment // and skip the whitespace in this case
// and skip the whitespace in this case if let Some((COMMENT, peek_text)) = trivias.peek().map(|(_, pair)| pair) {
if let Some((peek_kind, peek_text)) = let comment_kind = ast::CommentKind::from_text(peek_text);
trivias.peek().map(|(_, pair)| pair) if comment_kind.doc == Some(ast::CommentPlacement::Outer) {
{ continue;
if *peek_kind == COMMENT
&& peek_text.starts_with("///")
&& !peek_text.starts_with("////")
{
continue;
}
} }
break;
} }
break;
} }
COMMENT => { COMMENT => {
let comment_kind = ast::CommentKind::from_text(text);
if comment_kind.doc == Some(ast::CommentPlacement::Inner) {
break;
}
res = i + 1; res = i + 1;
} }
_ => (), _ => (),

View file

@ -1,9 +1,9 @@
SOURCE_FILE@0..93 SOURCE_FILE@0..93
COMMENT@0..60 "// https://github.com ..." COMMENT@0..60 "// https://github.com ..."
WHITESPACE@60..62 "\n\n" WHITESPACE@60..62 "\n\n"
MODULE@62..93 COMMENT@62..70 "//! docs"
COMMENT@62..70 "//! docs" WHITESPACE@70..71 "\n"
WHITESPACE@70..71 "\n" MODULE@71..93
COMMENT@71..82 "// non-docs" COMMENT@71..82 "// non-docs"
WHITESPACE@82..83 "\n" WHITESPACE@82..83 "\n"
MOD_KW@83..86 "mod" MOD_KW@83..86 "mod"