Skip to content
42 changes: 42 additions & 0 deletions clippy_utils/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use std::iter;
/// A `LitKind`-like enum to fold constant `Expr`s into.
#[derive(Debug, Clone)]
pub enum Constant {
/// A constant representing an algebraic data type
Adt(ConstValue),
/// A `String` (e.g., "abc").
Str(String),
Expand Down Expand Up @@ -206,6 +207,15 @@ impl Hash for Constant {
}

impl Constant {
/// Returns an ordering between `left` and `right`, if one exists. `cmp_type` determines
/// comparison behavior for constants with ambiguous typing (ex. [`Constant::Int`], which may be
/// signed or unsigned).
///
/// # Panics
///
/// Panics if the compared type is ambiguous and `cmp_type` describes a nonsensical type. For
/// example, if `left` and `right` are [`Constant::Int`], `cmp_type.kind()` must be either
/// [`Int`](ty::Int) or [`Uint`](ty::Uint).
pub fn partial_cmp(tcx: TyCtxt<'_>, cmp_type: Ty<'_>, left: &Self, right: &Self) -> Option<Ordering> {
match (left, right) {
(Self::Str(ls), Self::Str(rs)) => Some(ls.cmp(rs)),
Expand Down Expand Up @@ -276,6 +286,8 @@ impl Constant {
}
}

/// Consume [`Constant::Ref`], removing all references to return the contained expression, e.g.
/// `&&T` -> `T`.
#[must_use]
pub fn peel_refs(mut self) -> Self {
while let Constant::Ref(r) = self {
Expand All @@ -294,6 +306,8 @@ impl Constant {
Self::F128(f.to_bits())
}

/// Create a constant representing the minimum value of the type described by `ty`, if one
/// is defined.
pub fn new_numeric_min<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Self> {
match *ty.kind() {
ty::Uint(_) => Some(Self::Int(0)),
Expand All @@ -315,6 +329,8 @@ impl Constant {
}
}

/// Create a constant representing the maximum value of the type described by `ty`, if one
/// is defined.
pub fn new_numeric_max<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Self> {
match *ty.kind() {
ty::Uint(ty) => Some(Self::Int(match ty.normalize(tcx.sess.target.pointer_width) {
Expand Down Expand Up @@ -343,6 +359,8 @@ impl Constant {
}
}

/// Checks whether `self` is a numeric of the type `ty` and whether `self` is the minimum value
/// of that type.
pub fn is_numeric_min<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
match (self, ty.kind()) {
(&Self::Int(x), &ty::Uint(_)) => x == 0,
Expand All @@ -364,6 +382,8 @@ impl Constant {
}
}

/// Checks whether `self` is a numeric of the type `ty` and whether `self` is the maximum value
/// of that type.
pub fn is_numeric_max<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
match (self, ty.kind()) {
(&Self::Int(x), &ty::Uint(ty)) => {
Expand Down Expand Up @@ -395,6 +415,7 @@ impl Constant {
}
}

/// Checks whether `self` is a floating-point value representing positive infinity.
pub fn is_pos_infinity(&self) -> bool {
match *self {
// FIXME(f16_f128): add f16 and f128 when constants are available
Expand All @@ -404,6 +425,7 @@ impl Constant {
}
}

/// Checks whether `self` is a floating-point value representing negative infinity.
pub fn is_neg_infinity(&self) -> bool {
match *self {
// FIXME(f16_f128): add f16 and f128 when constants are available
Expand Down Expand Up @@ -451,14 +473,20 @@ pub enum ConstantSource {
NonLocal,
}
impl ConstantSource {
/// Checks whether this constant value is determined solely from its expression, and is not
/// dependent on another definition.
pub fn is_local(self) -> bool {
matches!(self, Self::Local)
}
}

/// An integer type (signed or unsigned) with enough bits to represent any integer that can be
/// represented in Rust.
#[derive(Copy, Clone, Debug, Eq)]
pub enum FullInt {
/// Signed full int
S(i128),
/// Unsigned full int
U(u128),
}

Expand Down Expand Up @@ -567,6 +595,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
}
}

/// Attempts to evaluate the given [pattern expression](PatExpr) as a [`Constant`].
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not entirely sure this is accurate?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? I think it is.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly don't remember. I think it was because the name of the function doesn't seem to imply that it has anything to do with constants?

pub fn eval_pat_expr(&self, pat_expr: &PatExpr<'_>) -> Option<Constant> {
match &pat_expr.kind {
PatExprKind::Lit { lit, negated } => {
Expand Down Expand Up @@ -1050,6 +1079,19 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
}
}

/// Converts a [`ConstValue`] to a [`Constant`], if possible.
///
/// - If `ty` is an [`Adt`](ty::Adt) describing a struct, returns a [`Constant::Adt`] containing
/// `val`.
/// - If `val` is a [`Int`](Scalar::Int) (which also includes booleans and raw pointers), `ty`
/// determines the variant of the returned constant. Returns `None` if `val` cannot be converted
/// to the type described by `ty`.
/// - If `ty` is a [`Ref`](ty::Ref) referring to a [`Str`](ty::Str) (i.e. a `&str`), returns a
/// [`Constant::Str`].
/// - If `val` is a [`ConstValue::Indirect`] and `ty` is an [`Array`](ty::Array) of
/// [`Float`](ty::Float), returns a [`Constant::Vec`]
///
/// Otherwise, returns `None`.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this function actually as particular as described or am I missing something

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you missed the Bool and RawPtr cases.

pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, val: ConstValue, ty: Ty<'tcx>) -> Option<Constant> {
match (val, ty.kind()) {
(_, &ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(val)),
Expand Down
3 changes: 3 additions & 0 deletions clippy_utils/src/higher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ impl<'hir> IfLetOrMatch<'hir> {
}
}

/// Returns the [expression](Expr) scrutinized by this `if let` or `match` expression.
pub fn scrutinee(&self) -> &'hir Expr<'hir> {
match self {
Self::Match(scrutinee, _, _) | Self::IfLet(scrutinee, _, _, _, _) => scrutinee,
Expand Down Expand Up @@ -321,6 +322,7 @@ pub struct While<'hir> {
pub body: &'hir Expr<'hir>,
/// Span of the loop header
pub span: Span,
/// The loop's label, if present
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pub label: Option<ast::Label>,
}

Expand Down Expand Up @@ -362,6 +364,7 @@ pub struct WhileLet<'hir> {
pub let_expr: &'hir Expr<'hir>,
/// `while let` loop body
pub if_then: &'hir Expr<'hir>,
/// The loop's label, if present
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pub label: Option<ast::Label>,
/// `while let PAT = EXPR`
/// ^^^^^^^^^^^^^^
Expand Down
7 changes: 7 additions & 0 deletions clippy_utils/src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Utilities for analyzing macro invocations and expansions.

#![allow(clippy::similar_names)] // `expr` and `expn`

use std::sync::{Arc, OnceLock};
Expand Down Expand Up @@ -65,6 +67,7 @@ pub struct MacroCall {
}

impl MacroCall {
/// Returns true if this macro call is from the root expansion or a locally defined macro
pub fn is_local(&self) -> bool {
span_is_local(self.span)
}
Expand Down Expand Up @@ -228,6 +231,7 @@ pub fn is_assert_macro(cx: &LateContext<'_>, def_id: DefId) -> bool {
matches!(name, sym::assert_macro | sym::debug_assert_macro)
}

/// An expansion of a `panic!()` expression into its arguments
#[derive(Debug)]
pub enum PanicExpn<'a> {
/// No arguments - `panic!()`
Expand All @@ -241,6 +245,7 @@ pub enum PanicExpn<'a> {
}

impl<'a> PanicExpn<'a> {
/// Parses a `panic!()` expression
pub fn parse(expr: &'a Expr<'a>) -> Option<Self> {
let ExprKind::Call(callee, args) = &expr.kind else {
return None;
Expand Down Expand Up @@ -516,7 +521,9 @@ pub enum FormatParamUsage {

/// A node with a `HirId` and a `Span`
pub trait HirNode {
/// Returns this node's [`HirId`]
fn hir_id(&self) -> HirId;
/// Returns this node's [`Span`]
fn span(&self) -> Span;
}

Expand Down
3 changes: 3 additions & 0 deletions clippy_utils/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ use std::sync::OnceLock;
/// arbitrary namespace
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum PathNS {
/// The [type namespace](TypeNS)
Type,
/// The [value namespace](ValueNS)
Value,
/// The [macro namespace](MacroNS)
Macro,

/// Resolves to the name in the first available namespace, e.g. for `std::vec` this would return
Expand Down
5 changes: 5 additions & 0 deletions clippy_utils/src/res.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Utilities for node resolution.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this fully describes this module?


use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{
Expand All @@ -10,6 +12,7 @@ use rustc_span::{Ident, Symbol};

/// Either a `HirId` or a type which can be identified by one.
pub trait HasHirId: Copy {
/// Returns the [`HirId`] identifying `self`.
fn hir_id(self) -> HirId;
}
impl HasHirId for HirId {
Expand All @@ -27,6 +30,7 @@ impl HasHirId for &Expr<'_> {

type DefRes = (DefKind, DefId);

/// Either a [`TypeckResults`] or a type that may contain one.
pub trait MaybeTypeckRes<'tcx> {
/// Gets the contained `TypeckResults`.
///
Expand Down Expand Up @@ -458,6 +462,7 @@ impl<'a, T: MaybeResPath<'a>> MaybeResPath<'a> for Option<T> {

/// A type which may either contain a `DefId` or be referred to by a `DefId`.
pub trait MaybeDef: Copy {
/// Gets the [`DefId`] contained by or referring to `self`
fn opt_def_id(self) -> Option<DefId>;

/// Gets this definition's id and kind. This will lookup the kind in the def
Expand Down
17 changes: 17 additions & 0 deletions clippy_utils/src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ use std::borrow::Cow;
use std::fmt;
use std::ops::{Deref, Index, Range};

/// Either a [`Session`] or a type which can be associated with one.
pub trait HasSession {
/// Gets the [`Session`] associated with `self`.
fn sess(&self) -> &Session;
}
impl HasSession for Session {
Expand All @@ -46,6 +48,7 @@ impl HasSession for LateContext<'_> {

/// Conversion of a value into the range portion of a `Span`.
pub trait SpanRange: Sized {
/// Converts `self` into the range portion of a [`Span`].
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure about this one

fn into_range(self) -> Range<BytePos>;
}
impl SpanRange for Span {
Expand All @@ -67,7 +70,9 @@ impl SpanRange for Range<BytePos> {

/// Conversion of a value into a `Span`
pub trait IntoSpan: Sized {
/// Converts `self` into a [`Span`].
fn into_span(self) -> Span;
/// Converts `self` into a [`Span`], with [context](SyntaxContext).
fn with_ctxt(self, ctxt: SyntaxContext) -> Span;
}
impl IntoSpan for Span {
Expand Down Expand Up @@ -95,6 +100,7 @@ impl IntoSpan for Range<BytePos> {
}
}

/// Extensions to [`SpanRange`].
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could probably be more descriptive

pub trait SpanRangeExt: SpanRange {
/// Attempts to get a handle to the source text. Returns `None` if either the span is malformed,
/// or the source text is not accessible.
Expand Down Expand Up @@ -338,8 +344,11 @@ fn trim_start(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> {
.unwrap_or(sp)
}

/// A range within a specific [source file](SourceFile).
pub struct SourceFileRange {
/// The [source file](SourceFile) referred to by this range
pub sf: Arc<SourceFile>,
/// The range within the associated [source file](SourceFile)
pub range: Range<usize>,
}
impl SourceFileRange {
Expand Down Expand Up @@ -441,6 +450,11 @@ pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option<String> {
// sources that the user has no control over.
// For some reason these attributes don't have any expansion info on them, so
// we have to check it this way until there is a better way.
//
/// Checks whether the code snippet referred to by the given [`Span`] is present in the source code.
///
/// For example, if the span refers to an attribute inserted during macro expansion, this will
/// return false.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this is accurate

pub fn is_present_in_source(sess: &impl HasSession, span: Span) -> bool {
if let Some(snippet) = snippet_opt(sess, span)
&& snippet.is_empty()
Expand Down Expand Up @@ -630,6 +644,9 @@ pub fn snippet_block_with_applicability(
reindent_multiline(&snip, true, indent)
}

/// Walks a span (from a block) up to the given context (using [`snippet_with_context()`]) and
/// converts it to a code snippet if available, otherwise use default. Adapts the applicability
/// level `app` by the rules of [`snippet_with_applicability()`].
pub fn snippet_block_with_context(
sess: &impl HasSession,
span: Span,
Expand Down
12 changes: 12 additions & 0 deletions clippy_utils/src/str_utils.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
//! Utilities for analyzing and transforming strings.

/// Dealing with string indices can be hard, this struct ensures that both the
/// character and byte index are provided for correct indexing.
///
/// `char_index` and `byte_index` *are not guaranteed* to agree with eachother.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct StrIndex {
/// The number of characters between the start of the `str` and this position
pub char_index: usize,
/// The number of bytes between the start of the `str` and this position
pub byte_index: usize,
}

impl StrIndex {
/// Creates a `StrIndex` from character and byte indices.
pub fn new(char_index: usize, byte_index: usize) -> Self {
Self { char_index, byte_index }
}
Expand Down Expand Up @@ -167,13 +174,18 @@ pub fn camel_case_split(s: &str) -> Vec<&str> {

/// Dealing with string comparison can be complicated, this struct ensures that both the
/// character and byte count are provided for correct indexing.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this mention that char_count and byte_count aren't guaranteed to agree with each other?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we already have a note at the beginning of the file, that shouldn't be necessary.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be nice to have it in the docs for the structs, since it'll show up in, for example, IDE hints.

///
/// `char_count` and `byte_count` *are not guaranteed* to agree with eachother.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct StrCount {
/// The number of characters in a string.
pub char_count: usize,
/// The number of bytes in a string.
pub byte_count: usize,
}

impl StrCount {
/// Creates a `StrCount` from character and byte counts.
pub fn new(char_count: usize, byte_count: usize) -> Self {
Self { char_count, byte_count }
}
Expand Down
1 change: 1 addition & 0 deletions clippy_utils/src/sugg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ impl<'a> Sugg<'a> {
}
}

/// Format this suggestion into a [`String`] to be displayed to the user.
pub fn into_string(self) -> String {
match self {
Sugg::NonParen(p) | Sugg::MaybeParen(p) => p.into_owned(),
Expand Down
Loading
Loading