compiler/rustc_ast/src/util/parser.rs RUST 221 lines View on github.com → Search inside
1use rustc_span::kw;23use crate::ast::{self, AssignOpKind, BinOpKind, RangeLimits};4use crate::token::{self, Token};56/// Associative operator.7#[derive(Copy, Clone, PartialEq, Debug)]8pub enum AssocOp {9    /// A binary op.10    Binary(BinOpKind),11    /// `?=` where ? is one of the assignable BinOps12    AssignOp(AssignOpKind),13    /// `=`14    Assign,15    /// `as`16    Cast,17    /// `..` or `..=` range18    Range(RangeLimits),19}2021#[derive(PartialEq, Debug)]22pub enum Fixity {23    /// The operator is left-associative24    Left,25    /// The operator is right-associative26    Right,27    /// The operator is not associative28    None,29}3031impl AssocOp {32    /// Creates a new AssocOp from a token.33    pub fn from_token(t: &Token) -> Option<AssocOp> {34        use AssocOp::*;35        match t.kind {36            token::Eq => Some(Assign),37            token::Plus => Some(Binary(BinOpKind::Add)),38            token::Minus => Some(Binary(BinOpKind::Sub)),39            token::Star => Some(Binary(BinOpKind::Mul)),40            token::Slash => Some(Binary(BinOpKind::Div)),41            token::Percent => Some(Binary(BinOpKind::Rem)),42            token::Caret => Some(Binary(BinOpKind::BitXor)),43            token::And => Some(Binary(BinOpKind::BitAnd)),44            token::Or => Some(Binary(BinOpKind::BitOr)),45            token::Shl => Some(Binary(BinOpKind::Shl)),46            token::Shr => Some(Binary(BinOpKind::Shr)),47            token::PlusEq => Some(AssignOp(AssignOpKind::AddAssign)),48            token::MinusEq => Some(AssignOp(AssignOpKind::SubAssign)),49            token::StarEq => Some(AssignOp(AssignOpKind::MulAssign)),50            token::SlashEq => Some(AssignOp(AssignOpKind::DivAssign)),51            token::PercentEq => Some(AssignOp(AssignOpKind::RemAssign)),52            token::CaretEq => Some(AssignOp(AssignOpKind::BitXorAssign)),53            token::AndEq => Some(AssignOp(AssignOpKind::BitAndAssign)),54            token::OrEq => Some(AssignOp(AssignOpKind::BitOrAssign)),55            token::ShlEq => Some(AssignOp(AssignOpKind::ShlAssign)),56            token::ShrEq => Some(AssignOp(AssignOpKind::ShrAssign)),57            token::Lt => Some(Binary(BinOpKind::Lt)),58            token::Le => Some(Binary(BinOpKind::Le)),59            token::Ge => Some(Binary(BinOpKind::Ge)),60            token::Gt => Some(Binary(BinOpKind::Gt)),61            token::EqEq => Some(Binary(BinOpKind::Eq)),62            token::Ne => Some(Binary(BinOpKind::Ne)),63            token::AndAnd => Some(Binary(BinOpKind::And)),64            token::OrOr => Some(Binary(BinOpKind::Or)),65            token::DotDot => Some(Range(RangeLimits::HalfOpen)),66            // DotDotDot is no longer supported, but we need some way to display the error67            token::DotDotEq | token::DotDotDot => Some(Range(RangeLimits::Closed)),68            // `<-` should probably be `< -`69            token::LArrow => Some(Binary(BinOpKind::Lt)),70            _ if t.is_keyword(kw::As) => Some(Cast),71            _ => None,72        }73    }7475    /// Gets the precedence of this operator76    pub fn precedence(&self) -> ExprPrecedence {77        use AssocOp::*;78        match *self {79            Cast => ExprPrecedence::Cast,80            Binary(bin_op) => bin_op.precedence(),81            Range(_) => ExprPrecedence::Range,82            Assign | AssignOp(_) => ExprPrecedence::Assign,83        }84    }8586    /// Gets the fixity of this operator87    pub fn fixity(&self) -> Fixity {88        use AssocOp::*;89        // NOTE: it is a bug to have an operators that has same precedence but different fixities!90        match *self {91            Assign | AssignOp(_) => Fixity::Right,92            Binary(binop) => binop.fixity(),93            Cast => Fixity::Left,94            Range(_) => Fixity::None,95        }96    }9798    pub fn is_comparison(&self) -> bool {99        use AssocOp::*;100        match *self {101            Binary(binop) => binop.is_comparison(),102            Assign | AssignOp(_) | Cast | Range(_) => false,103        }104    }105106    pub fn is_assign_like(&self) -> bool {107        use AssocOp::*;108        match *self {109            Assign | AssignOp(_) => true,110            Cast | Binary(_) | Range(_) => false,111        }112    }113114    /// This operator could be used to follow a block unambiguously.115    ///116    /// This is used for error recovery at the moment, providing a suggestion to wrap blocks with117    /// parentheses while having a high degree of confidence on the correctness of the suggestion.118    pub fn can_continue_expr_unambiguously(&self) -> bool {119        use AssocOp::*;120        use BinOpKind::*;121        matches!(122            self,123            Assign | // `{ 42 } = { 42 }`124            Binary(125                BitXor | // `{ 42 } ^ 3`126                Div | // `{ 42 } / 42`127                Rem | // `{ 42 } % 2`128                Shr | // `{ 42 } >> 2`129                Le | // `{ 42 } <= 3`130                Gt | // `{ 42 } > 3`131                Ge   // `{ 42 } >= 3`132            ) |133            AssignOp(_) | // `{ 42 } +=`134            // Equal | // `{ 42 } == { 42 }`    Accepting these here would regress incorrect135            // NotEqual | // `{ 42 } != { 42 }  struct literals parser recovery.136            Cast // `{ 42 } as usize`137        )138    }139}140141#[derive(Clone, Copy, PartialEq, PartialOrd)]142pub enum ExprPrecedence {143    // return, break, yield, closures144    Jump,145    // = += -= *= /= %= &= |= ^= <<= >>=146    Assign,147    // .. ..=148    Range,149    // ||150    LOr,151    // &&152    LAnd,153    // == != < > <= >=154    Compare,155    // |156    BitOr,157    // ^158    BitXor,159    // &160    BitAnd,161    // << >>162    Shift,163    // + -164    Sum,165    // * / %166    Product,167    // as168    Cast,169    // unary - * ! & &mut170    Prefix,171    // paths, loops, function calls, array indexing, field expressions, method calls172    Unambiguous,173}174175/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.176pub fn prec_let_scrutinee_needs_par() -> ExprPrecedence {177    ExprPrecedence::LAnd178}179180/// Suppose we have `let _ = e` and the `order` of `e`.181/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS?182///183/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.184/// Can we print this as `let _ = a OP b`?185pub fn needs_par_as_let_scrutinee(order: ExprPrecedence) -> bool {186    order <= prec_let_scrutinee_needs_par()187}188189/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any190/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and191/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.192pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {193    match &value.kind {194        ast::ExprKind::Struct(..) => true,195196        ast::ExprKind::Assign(lhs, rhs, _)197        | ast::ExprKind::AssignOp(_, lhs, rhs)198        | ast::ExprKind::Binary(_, lhs, rhs) => {199            // X { y: 1 } + X { y: 2 }200            contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)201        }202        ast::ExprKind::Await(x, _)203        | ast::ExprKind::Unary(_, x)204        | ast::ExprKind::Cast(x, _)205        | ast::ExprKind::Type(x, _)206        | ast::ExprKind::Field(x, _)207        | ast::ExprKind::Index(x, _, _)208        | ast::ExprKind::Match(x, _, ast::MatchKind::Postfix) => {209            // &X { y: 1 }, X { y: 1 }.y210            contains_exterior_struct_lit(x)211        }212213        ast::ExprKind::MethodCall(box ast::MethodCall { receiver, .. }) => {214            // X { y: 1 }.bar(...)215            contains_exterior_struct_lit(receiver)216        }217218        _ => false,219    }220}

Code quality findings 7

Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use AssocOp::*;
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use AssocOp::*;
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use AssocOp::*;
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use AssocOp::*;
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use AssocOp::*;
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use AssocOp::*;
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use BinOpKind::*;

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.