11pub use CommentStyle :: * ;
22
3- use crate :: ast;
3+ use crate :: ast:: AttrStyle ;
4+ use crate :: token:: CommentKind ;
45use rustc_span:: source_map:: SourceMap ;
56use rustc_span:: { BytePos , CharPos , FileName , Pos , Symbol } ;
67
7- use log:: debug;
8-
98#[ cfg( test) ]
109mod tests;
1110
@@ -28,43 +27,46 @@ pub struct Comment {
2827 pub pos : BytePos ,
2928}
3029
31- pub fn is_line_doc_comment ( s : & str ) -> bool {
32- let res = ( s. starts_with ( "///" ) && * s. as_bytes ( ) . get ( 3 ) . unwrap_or ( & b' ' ) != b'/' )
33- || s. starts_with ( "//!" ) ;
34- debug ! ( "is {:?} a doc comment? {}" , s, res) ;
35- res
36- }
37-
38- pub fn is_block_doc_comment ( s : & str ) -> bool {
39- // Prevent `/**/` from being parsed as a doc comment
40- let res = ( ( s. starts_with ( "/**" ) && * s. as_bytes ( ) . get ( 3 ) . unwrap_or ( & b' ' ) != b'*' )
41- || s. starts_with ( "/*!" ) )
42- && s. len ( ) >= 5 ;
43- debug ! ( "is {:?} a doc comment? {}" , s, res) ;
44- res
45- }
46-
47- // FIXME(#64197): Try to privatize this again.
48- pub fn is_doc_comment ( s : & str ) -> bool {
49- ( s. starts_with ( "///" ) && is_line_doc_comment ( s) )
50- || s. starts_with ( "//!" )
51- || ( s. starts_with ( "/**" ) && is_block_doc_comment ( s) )
52- || s. starts_with ( "/*!" )
30+ /// For a full line comment string returns its doc comment style if it's a doc comment
31+ /// and returns `None` if it's a regular comment.
32+ pub fn line_doc_comment_style ( line_comment : & str ) -> Option < AttrStyle > {
33+ let line_comment = line_comment. as_bytes ( ) ;
34+ assert ! ( line_comment. starts_with( b"//" ) ) ;
35+ match line_comment. get ( 2 ) {
36+ // `//!` is an inner line doc comment.
37+ Some ( b'!' ) => Some ( AttrStyle :: Inner ) ,
38+ Some ( b'/' ) => match line_comment. get ( 3 ) {
39+ // `////` (more than 3 slashes) is not considered a doc comment.
40+ Some ( b'/' ) => None ,
41+ // Otherwise `///` is an outer line doc comment.
42+ _ => Some ( AttrStyle :: Outer ) ,
43+ } ,
44+ _ => None ,
45+ }
5346}
5447
55- pub fn doc_comment_style ( comment : Symbol ) -> ast:: AttrStyle {
56- let comment = & comment. as_str ( ) ;
57- assert ! ( is_doc_comment( comment) ) ;
58- if comment. starts_with ( "//!" ) || comment. starts_with ( "/*!" ) {
59- ast:: AttrStyle :: Inner
60- } else {
61- ast:: AttrStyle :: Outer
48+ /// For a full block comment string returns its doc comment style if it's a doc comment
49+ /// and returns `None` if it's a regular comment.
50+ pub fn block_doc_comment_style ( block_comment : & str , terminated : bool ) -> Option < AttrStyle > {
51+ let block_comment = block_comment. as_bytes ( ) ;
52+ assert ! ( block_comment. starts_with( b"/*" ) ) ;
53+ assert ! ( !terminated || block_comment. ends_with( b"*/" ) ) ;
54+ match block_comment. get ( 2 ) {
55+ // `/*!` is an inner block doc comment.
56+ Some ( b'!' ) => Some ( AttrStyle :: Inner ) ,
57+ Some ( b'*' ) => match block_comment. get ( 3 ) {
58+ // `/***` (more than 2 stars) is not considered a doc comment.
59+ Some ( b'*' ) => None ,
60+ // `/**/` is not considered a doc comment.
61+ Some ( b'/' ) if block_comment. len ( ) == 4 => None ,
62+ // Otherwise `/**` is an outer block doc comment.
63+ _ => Some ( AttrStyle :: Outer ) ,
64+ } ,
65+ _ => None ,
6266 }
6367}
6468
65- pub fn strip_doc_comment_decoration ( comment : Symbol ) -> String {
66- let comment = & comment. as_str ( ) ;
67-
69+ pub fn strip_doc_comment_decoration ( data : Symbol , comment_kind : CommentKind ) -> String {
6870 /// remove whitespace-only lines from the start/end of lines
6971 fn vertical_trim ( lines : Vec < String > ) -> Vec < String > {
7072 let mut i = 0 ;
@@ -126,26 +128,19 @@ pub fn strip_doc_comment_decoration(comment: Symbol) -> String {
126128 }
127129 }
128130
129- // one-line comments lose their prefix
130- const ONELINERS : & [ & str ] = & [ "///!" , "///" , "//!" , "//" ] ;
131-
132- for prefix in ONELINERS {
133- if comment. starts_with ( * prefix) {
134- return ( & comment[ prefix. len ( ) ..] ) . to_string ( ) ;
131+ match comment_kind {
132+ CommentKind :: Line => {
133+ let data = data. as_str ( ) ;
134+ let prefix_len = if data. starts_with ( '!' ) { 1 } else { 0 } ;
135+ data[ prefix_len..] . to_string ( )
136+ }
137+ CommentKind :: Block => {
138+ let lines = data. as_str ( ) . lines ( ) . map ( |s| s. to_string ( ) ) . collect :: < Vec < String > > ( ) ;
139+ let lines = vertical_trim ( lines) ;
140+ let lines = horizontal_trim ( lines) ;
141+ lines. join ( "\n " )
135142 }
136143 }
137-
138- if comment. starts_with ( "/*" ) {
139- let lines =
140- comment[ 3 ..comment. len ( ) - 2 ] . lines ( ) . map ( |s| s. to_string ( ) ) . collect :: < Vec < String > > ( ) ;
141-
142- let lines = vertical_trim ( lines) ;
143- let lines = horizontal_trim ( lines) ;
144-
145- return lines. join ( "\n " ) ;
146- }
147-
148- panic ! ( "not a doc-comment: {}" , comment) ;
149144}
150145
151146/// Returns `None` if the first `col` chars of `s` contain a non-whitespace char.
@@ -226,8 +221,8 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
226221 }
227222 }
228223 }
229- rustc_lexer:: TokenKind :: BlockComment { terminated : _ } => {
230- if ! is_block_doc_comment ( token_text) {
224+ rustc_lexer:: TokenKind :: BlockComment { terminated } => {
225+ if block_doc_comment_style ( token_text, terminated ) . is_none ( ) {
231226 let code_to_the_right = match text[ pos + token. len ..] . chars ( ) . next ( ) {
232227 Some ( '\r' | '\n' ) => false ,
233228 _ => true ,
@@ -249,7 +244,7 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
249244 }
250245 }
251246 rustc_lexer:: TokenKind :: LineComment => {
252- if ! is_doc_comment ( token_text) {
247+ if line_doc_comment_style ( token_text) . is_none ( ) {
253248 comments. push ( Comment {
254249 style : if code_to_the_left { Trailing } else { Isolated } ,
255250 lines : vec ! [ token_text. to_string( ) ] ,
0 commit comments