@@ -254,11 +254,11 @@ fn document_features_impl(args: &Args) -> Result<TokenStream, TokenStream> {
254
254
let mut cargo_toml = std:: fs:: read_to_string ( Path :: new ( & path) . join ( "Cargo.toml" ) )
255
255
. map_err ( |e| error ( & format ! ( "Can't open Cargo.toml: {:?}" , e) ) ) ?;
256
256
257
- if !cargo_toml . contains ( " \n ##" ) && ! cargo_toml. contains ( " \n #!" ) {
257
+ if !has_doc_comments ( & cargo_toml) {
258
258
// On crates.io, Cargo.toml is usually "normalized" and stripped of all comments.
259
259
// The original Cargo.toml has been renamed Cargo.toml.orig
260
260
if let Ok ( orig) = std:: fs:: read_to_string ( Path :: new ( & path) . join ( "Cargo.toml.orig" ) ) {
261
- if orig . contains ( "##" ) || orig. contains ( "#!" ) {
261
+ if has_doc_comments ( & orig) {
262
262
cargo_toml = orig;
263
263
}
264
264
}
@@ -268,6 +268,109 @@ fn document_features_impl(args: &Args) -> Result<TokenStream, TokenStream> {
268
268
Ok ( std:: iter:: once ( proc_macro:: TokenTree :: from ( proc_macro:: Literal :: string ( & result) ) ) . collect ( ) )
269
269
}
270
270
271
+ /// Check if the Cargo.toml has comments that looks like doc comments.
272
+ fn has_doc_comments ( cargo_toml : & str ) -> bool {
273
+ let mut lines = cargo_toml. lines ( ) . map ( str:: trim) ;
274
+ while let Some ( line) = lines. next ( ) {
275
+ if line. starts_with ( "## " ) || line. starts_with ( "#! " ) {
276
+ return true ;
277
+ }
278
+ let before_coment = line. split_once ( '#' ) . map_or ( line, |( before, _) | before) ;
279
+ if line. starts_with ( "#" ) {
280
+ continue ;
281
+ }
282
+ if let Some ( ( _, mut quote) ) = before_coment. split_once ( "\" \" \" " ) {
283
+ loop {
284
+ // skip slashes.
285
+ if let Some ( ( _, s) ) = quote. split_once ( '\\' ) {
286
+ quote = s. strip_prefix ( '\\' ) . or_else ( || s. strip_prefix ( '"' ) ) . unwrap_or ( s) ;
287
+ continue ;
288
+ }
289
+ // skip quotes.
290
+ if let Some ( ( _, out_quote) ) = quote. split_once ( "\" \" \" " ) {
291
+ let out_quote = out_quote. trim_start_matches ( '"' ) ;
292
+ let out_quote =
293
+ out_quote. split_once ( '#' ) . map_or ( out_quote, |( before, _) | before) ;
294
+ if let Some ( ( _, q) ) = out_quote. split_once ( "\" \" \" " ) {
295
+ quote = q;
296
+ continue ;
297
+ }
298
+ break ;
299
+ } ;
300
+ match lines. next ( ) {
301
+ Some ( l) => quote = l,
302
+ None => return false ,
303
+ }
304
+ }
305
+ }
306
+ }
307
+ false
308
+ }
309
+
310
+ #[ test]
311
+ fn test_has_doc_coment ( ) {
312
+ assert ! ( has_doc_comments( "foo\n bar\n ## comment\n ddd" ) ) ;
313
+ assert ! ( !has_doc_comments( "foo\n bar\n #comment\n ddd" ) ) ;
314
+ assert ! ( !has_doc_comments(
315
+ r#"
316
+ [[package.metadata.release.pre-release-replacements]]
317
+ exactly = 1 # not a doc comment
318
+ file = "CHANGELOG.md"
319
+ replace = """
320
+ <!-- next-header -->
321
+ ## [Unreleased] - ReleaseDate
322
+ """
323
+ search = "<!-- next-header -->"
324
+ array = ["""foo""", """
325
+ bar""", """eee
326
+ ## not a comment
327
+ """]
328
+ "#
329
+ ) ) ;
330
+ assert ! ( has_doc_comments(
331
+ r#"
332
+ [[package.metadata.release.pre-release-replacements]]
333
+ exactly = 1 # """
334
+ file = "CHANGELOG.md"
335
+ replace = """
336
+ <!-- next-header -->
337
+ ## [Unreleased] - ReleaseDate
338
+ """
339
+ search = "<!-- next-header -->"
340
+ array = ["""foo""", """
341
+ bar""", """eee
342
+ ## not a comment
343
+ """]
344
+ ## This is a comment
345
+ feature = "45"
346
+ "#
347
+ ) ) ;
348
+
349
+ assert ! ( !has_doc_comments(
350
+ r#"
351
+ [[package.metadata.release.pre-release-replacements]]
352
+ value = """" string \"""
353
+ ## within the string
354
+ \""""
355
+ another_string = """"" # """
356
+ ## also within"""
357
+ "#
358
+ ) ) ;
359
+
360
+ assert ! ( has_doc_comments(
361
+ r#"
362
+ [[package.metadata.release.pre-release-replacements]]
363
+ value = """" string \"""
364
+ ## within the string
365
+ \""""
366
+ another_string = """"" # """
367
+ ## also within"""
368
+ ## out of the string
369
+ foo = bar
370
+ "#
371
+ ) ) ;
372
+ }
373
+
271
374
fn process_toml ( cargo_toml : & str , args : & Args ) -> Result < String , String > {
272
375
// Get all lines between the "[features]" and the next block
273
376
let mut lines = cargo_toml
0 commit comments