mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-16 21:15:18 +03:00
d42a92b18d
* Lint doc comments in cfg_select branches * test with multi-line doc comment Co-authored-by: Copilot <copilot@github.com> * Reject outer attributes on `cfg_select` branches * address nits and gotchas Co-authored-by: Copilot <copilot@github.com> * one more test Co-authored-by: Copilot <copilot@github.com> * avoid snapshotting and classify recovered doc comments directly
76 lines
2.9 KiB
Rust
76 lines
2.9 KiB
Rust
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
|
use rustc_ast::util::classify;
|
|
use rustc_ast::{AttrKind, token};
|
|
use rustc_errors::PResult;
|
|
use rustc_span::Span;
|
|
|
|
use crate::exp;
|
|
use crate::parser::{AttrWrapper, ForceCollect, Parser, Restrictions, Trailing, UsePreAttrPos};
|
|
|
|
#[derive(Default)]
|
|
pub struct CfgSelectBranchAttrSpans {
|
|
pub attrs: Vec<Span>,
|
|
pub doc_comments: Vec<Span>,
|
|
}
|
|
|
|
impl<'a> Parser<'a> {
|
|
/// Parses a `TokenTree` consisting either of `{ /* ... */ }` optionally followed by a comma
|
|
/// (and strip the braces and the optional comma) or an expression followed by a comma
|
|
/// (and strip the comma).
|
|
pub fn parse_delimited_token_tree(&mut self) -> PResult<'a, TokenStream> {
|
|
if self.token == token::OpenBrace {
|
|
// Strip the outer '{' and '}'.
|
|
match self.parse_token_tree() {
|
|
TokenTree::Token(..) => unreachable!("because the current token is a '{{'"),
|
|
TokenTree::Delimited(.., tts) => {
|
|
// Optionally end with a comma.
|
|
let _ = self.eat(exp!(Comma));
|
|
return Ok(tts);
|
|
}
|
|
}
|
|
}
|
|
let expr = self.collect_tokens(None, AttrWrapper::empty(), ForceCollect::Yes, |p, _| {
|
|
p.parse_expr_res(Restrictions::STMT_EXPR, AttrWrapper::empty())
|
|
.map(|(expr, _)| (expr, Trailing::No, UsePreAttrPos::No))
|
|
})?;
|
|
if !classify::expr_is_complete(&expr)
|
|
&& self.token != token::CloseBrace
|
|
&& self.token != token::Eof
|
|
{
|
|
self.expect(exp!(Comma))?;
|
|
} else {
|
|
let _ = self.eat(exp!(Comma));
|
|
}
|
|
Ok(TokenStream::from_ast(&expr))
|
|
}
|
|
|
|
/// Parses outer attributes before a `cfg_select!` branch for recovery.
|
|
pub fn parse_cfg_select_branch_outer_attrs(
|
|
&mut self,
|
|
) -> PResult<'a, Option<CfgSelectBranchAttrSpans>> {
|
|
let attrs = self.parse_outer_attributes()?;
|
|
if attrs.is_empty() {
|
|
return Ok(None);
|
|
}
|
|
|
|
let mut spans = CfgSelectBranchAttrSpans::default();
|
|
for attr in attrs.take_for_recovery(self.psess) {
|
|
match attr.kind {
|
|
AttrKind::Normal(..) => spans.attrs.push(attr.span),
|
|
// `parse_outer_attributes` already emitted E0753 for inner doc comments before
|
|
// recovering them as outer doc-comment attributes.
|
|
AttrKind::DocComment(comment_kind, _)
|
|
if self.span_to_snippet(attr.span).ok().is_some_and(
|
|
|snippet| match comment_kind {
|
|
token::CommentKind::Line => snippet.starts_with("//!"),
|
|
token::CommentKind::Block => snippet.starts_with("/*!"),
|
|
},
|
|
) => {}
|
|
AttrKind::DocComment(..) => spans.doc_comments.push(attr.span),
|
|
}
|
|
}
|
|
|
|
Ok(Some(spans))
|
|
}
|
|
}
|