+
+fn eq_label_lt(lt1: &Option<ast::Lifetime>, lt2: &Option<ast::Lifetime>) -> bool {
+ lt1.as_ref().zip(lt2.as_ref()).map_or(false, |(lt, lbl)| lt.text() == lbl.text())
+}
+
+struct TreeWithDepthIterator {
+ preorder: Preorder<RustLanguage>,
+ depth: i32,
+}
+
+impl TreeWithDepthIterator {
+ fn new(body: ast::StmtList) -> Self {
+ let preorder = body.syntax().preorder();
+ Self { preorder, depth: 0 }
+ }
+}
+
+impl<'a> Iterator for TreeWithDepthIterator {
+ type Item = (ast::Expr, i32);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ while let Some((event, expr)) = self.preorder.find_map(|ev| match ev {
+ WalkEvent::Enter(it) => Some(WalkEvent::Enter(())).zip(ast::Expr::cast(it)),
+ WalkEvent::Leave(it) => Some(WalkEvent::Leave(())).zip(ast::Expr::cast(it)),
+ }) {
+ match (event, expr) {
+ (
+ WalkEvent::Enter(_),
+ ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_),
+ ) => {
+ self.depth += 1;
+ }
+ (
+ WalkEvent::Leave(_),
+ ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_),
+ ) => {
+ self.depth -= 1;
+ }
+ (WalkEvent::Enter(_), ast::Expr::BlockExpr(e)) if e.label().is_some() => {
+ self.depth += 1;
+ }
+ (WalkEvent::Leave(_), ast::Expr::BlockExpr(e)) if e.label().is_some() => {
+ self.depth -= 1;
+ }
+ (WalkEvent::Enter(_), expr) => return Some((expr, self.depth)),
+ _ => (),
+ }
+ }
+ None
+ }
+}
+
+/// Checks if the given lint is equal or is contained by the other lint which may or may not be a group.
+pub fn lint_eq_or_in_group(lint: &str, lint_is: &str) -> bool {
+ if lint == lint_is {
+ return true;
+ }
+
+ if let Some(group) = generated_lints::DEFAULT_LINT_GROUPS
+ .iter()
+ .chain(generated_lints::CLIPPY_LINT_GROUPS.iter())
+ .chain(generated_lints::RUSTDOC_LINT_GROUPS.iter())
+ .find(|&check| check.lint.label == lint_is)
+ {
+ group.children.contains(&lint)
+ } else {
+ false
+ }
+}
+
+/// Parses the input token tree as comma separated plain paths.
+pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option<Vec<ast::Path>> {
+ let r_paren = input.r_paren_token();
+ let tokens =
+ input.syntax().children_with_tokens().skip(1).map_while(|it| match it.into_token() {
+ // seeing a keyword means the attribute is unclosed so stop parsing here
+ Some(tok) if tok.kind().is_keyword() => None,
+ // don't include the right token tree parenthesis if it exists
+ tok @ Some(_) if tok == r_paren => None,
+ // only nodes that we can find are other TokenTrees, those are unexpected in this parse though
+ None => None,
+ Some(tok) => Some(tok),
+ });
+ let input_expressions = tokens.into_iter().group_by(|tok| tok.kind() == T![,]);
+ let paths = input_expressions
+ .into_iter()
+ .filter_map(|(is_sep, group)| (!is_sep).then(|| group))
+ .filter_map(|mut tokens| {
+ syntax::hacks::parse_expr_from_str(&tokens.join("")).and_then(|expr| match expr {
+ ast::Expr::PathExpr(it) => it.path(),
+ _ => None,
+ })
+ })
+ .collect();
+ Some(paths)
+}