compiler/rustc_borrowck/src/places_conflict.rs RUST 527 lines View on github.com → Search inside
1//! The borrowck rules for proving disjointness are applied from the "root" of the2//! borrow forwards, iterating over "similar" projections in lockstep until3//! we can prove overlap one way or another. Essentially, we treat `Overlap` as4//! a monoid and report a conflict if the product ends up not being `Disjoint`.5//!6//! On each step, if we didn't run out of borrow or place, we know that our elements7//! have the same type, and that they only overlap if they are the identical.8//!9//! For example, if we are comparing these:10//! ```text11//! BORROW:  (*x1[2].y).z.a12//! ACCESS:  (*x1[i].y).w.b13//! ```14//!15//! Then our steps are:16//! ```text17//!       x1         |   x1          -- places are the same18//!       x1[2]      |   x1[i]       -- equal or disjoint (disjoint if indexes differ)19//!       x1[2].y    |   x1[i].y     -- equal or disjoint20//!      *x1[2].y    |  *x1[i].y     -- equal or disjoint21//!     (*x1[2].y).z | (*x1[i].y).w  -- we are disjoint and don't need to check more!22//! ```23//!24//! Because `zip` does potentially bad things to the iterator inside, this loop25//! also handles the case where the access might be a *prefix* of the borrow, e.g.26//!27//! ```text28//! BORROW:  (*x1[2].y).z.a29//! ACCESS:  x1[i].y30//! ```31//!32//! Then our steps are:33//! ```text34//!       x1         |   x1          -- places are the same35//!       x1[2]      |   x1[i]       -- equal or disjoint (disjoint if indexes differ)36//!       x1[2].y    |   x1[i].y     -- equal or disjoint37//! ```38//!39//! -- here we run out of access - the borrow can access a part of it. If this40//! is a full deep access, then we *know* the borrow conflicts with it. However,41//! if the access is shallow, then we can proceed:42//!43//! ```text44//!       x1[2].y    | (*x1[i].y)    -- a deref! the access can't get past this, so we45//!                                     are disjoint46//! ```47//!48//! Our invariant is, that at each step of the iteration:49//!  - If we didn't run out of access to match, our borrow and access are comparable50//!    and either equal or disjoint.51//!  - If we did run out of access, the borrow can access a part of it.5253use std::cmp::max;54use std::iter;5556use rustc_hir as hir;57use rustc_middle::bug;58use rustc_middle::mir::{59    Body, BorrowKind, FakeBorrowKind, MutBorrowKind, Place, PlaceElem, PlaceRef, ProjectionElem,60};61use rustc_middle::ty::{self, TyCtxt};62use tracing::{debug, instrument};6364use crate::{AccessDepth, ArtificialField, Deep, Overlap, Shallow};6566/// When checking if a place conflicts with another place, this enum is used to influence decisions67/// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`.68/// `PlaceConflictBias::Overlap` would bias toward assuming that `i` might equal `j` and that these69/// places overlap. `PlaceConflictBias::NoOverlap` assumes that for the purposes of the predicate70/// being run in the calling context, the conservative choice is to assume the compared indices71/// are disjoint (and therefore, do not overlap).72#[derive(Copy, Clone, Debug, Eq, PartialEq)]73pub enum PlaceConflictBias {74    Overlap,75    NoOverlap,76}7778/// Helper function for checking if places conflict with a mutable borrow and deep access depth.79/// This is used to check for places conflicting outside of the borrow checking code (such as in80/// dataflow).81pub fn places_conflict<'tcx>(82    tcx: TyCtxt<'tcx>,83    body: &Body<'tcx>,84    borrow_place: Place<'tcx>,85    access_place: Place<'tcx>,86    bias: PlaceConflictBias,87) -> bool {88    borrow_conflicts_with_place(89        tcx,90        body,91        borrow_place,92        BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow },93        access_place.as_ref(),94        AccessDepth::Deep,95        bias,96    )97}9899/// Checks whether the `borrow_place` conflicts with the `access_place` given a borrow kind and100/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime101/// array indices, for example) should be interpreted - this depends on what the caller wants in102/// order to make the conservative choice and preserve soundness.103#[inline]104pub(super) fn borrow_conflicts_with_place<'tcx>(105    tcx: TyCtxt<'tcx>,106    body: &Body<'tcx>,107    borrow_place: Place<'tcx>,108    borrow_kind: BorrowKind,109    access_place: PlaceRef<'tcx>,110    access: AccessDepth,111    bias: PlaceConflictBias,112) -> bool {113    let borrow_local = borrow_place.local;114    let access_local = access_place.local;115116    if borrow_local != access_local {117        // We have proven the borrow disjoint - further projections will remain disjoint.118        return false;119    }120121    // This Local/Local case is handled by the more general code below, but122    // it's so common that it's a speed win to check for it first.123    if borrow_place.projection.is_empty() && access_place.projection.is_empty() {124        return true;125    }126127    place_components_conflict(tcx, body, borrow_place, borrow_kind, access_place, access, bias)128}129130#[instrument(level = "debug", skip(tcx, body))]131fn place_components_conflict<'tcx>(132    tcx: TyCtxt<'tcx>,133    body: &Body<'tcx>,134    borrow_place: Place<'tcx>,135    borrow_kind: BorrowKind,136    access_place: PlaceRef<'tcx>,137    access: AccessDepth,138    bias: PlaceConflictBias,139) -> bool {140    let borrow_local = borrow_place.local;141    let access_local = access_place.local;142    // borrow_conflicts_with_place should have checked that.143    assert_eq!(borrow_local, access_local);144145    // loop invariant: borrow_c is always either equal to access_c or disjoint from it.146    for ((borrow_place, borrow_c), &access_c) in147        iter::zip(borrow_place.iter_projections(), access_place.projection)148    {149        debug!(?borrow_c, ?access_c);150151        // Borrow and access path both have more components.152        //153        // Examples:154        //155        // - borrow of `a.(...)`, access to `a.(...)`156        // - borrow of `a.(...)`, access to `b.(...)`157        //158        // Here we only see the components we have checked so159        // far (in our examples, just the first component). We160        // check whether the components being borrowed vs161        // accessed are disjoint (as in the second example,162        // but not the first).163        match place_projection_conflict(tcx, body, borrow_place, borrow_c, access_c, bias) {164            Overlap::Arbitrary => {165                // We have encountered different fields of potentially166                // the same union - the borrow now partially overlaps.167                //168                // There is no *easy* way of comparing the fields169                // further on, because they might have different types170                // (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and171                // `.y` come from different structs).172                //173                // We could try to do some things here - e.g., count174                // dereferences - but that's probably not a good175                // idea, at least for now, so just give up and176                // report a conflict. This is unsafe code anyway so177                // the user could always use raw pointers.178                debug!("arbitrary -> conflict");179                return true;180            }181            Overlap::EqualOrDisjoint => {182                // This is the recursive case - proceed to the next element.183            }184            Overlap::Disjoint => {185                // We have proven the borrow disjoint - further186                // projections will remain disjoint.187                debug!("disjoint");188                return false;189            }190        }191    }192193    if borrow_place.projection.len() > access_place.projection.len() {194        for (base, elem) in borrow_place.iter_projections().skip(access_place.projection.len()) {195            // Borrow path is longer than the access path. Examples:196            //197            // - borrow of `a.b.c`, access to `a.b`198            //199            // Here, we know that the borrow can access a part of200            // our place. This is a conflict if that is a part our201            // access cares about.202203            let base_ty = base.ty(body, tcx).ty;204205            match (elem, base_ty.kind(), access) {206                (_, _, Shallow(Some(ArtificialField::ArrayLength)))207                | (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => {208                    // The array length is like additional fields on the209                    // type; it does not overlap any existing data there.210                    // Furthermore, if cannot actually be a prefix of any211                    // borrowed place (at least in MIR as it is currently.)212                    //213                    // e.g., a (mutable) borrow of `a[5]` while we read the214                    // array length of `a`.215                    debug!("borrow_conflicts_with_place: implicit field");216                    return false;217                }218219                (ProjectionElem::Deref, _, Shallow(None)) => {220                    // e.g., a borrow of `*x.y` while we shallowly access `x.y` or some221                    // prefix thereof - the shallow access can't touch anything behind222                    // the pointer.223                    debug!("borrow_conflicts_with_place: shallow access behind ptr");224                    return false;225                }226                (ProjectionElem::Deref, ty::Ref(_, _, hir::Mutability::Not), _) => {227                    // Shouldn't be tracked228                    bug!("Tracking borrow behind shared reference.");229                }230                (ProjectionElem::Deref, ty::Ref(_, _, hir::Mutability::Mut), AccessDepth::Drop) => {231                    // Values behind a mutable reference are not access either by dropping a232                    // value, or by StorageDead233                    debug!("borrow_conflicts_with_place: drop access behind ptr");234                    return false;235                }236237                (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => {238                    // Drop can read/write arbitrary projections, so places239                    // conflict regardless of further projections.240                    if def.has_dtor(tcx) {241                        return true;242                    }243                }244245                (ProjectionElem::Deref, _, Deep)246                | (ProjectionElem::Deref, _, AccessDepth::Drop)247                | (ProjectionElem::Field { .. }, _, _)248                | (ProjectionElem::Index { .. }, _, _)249                | (ProjectionElem::ConstantIndex { .. }, _, _)250                | (ProjectionElem::Subslice { .. }, _, _)251                | (ProjectionElem::OpaqueCast { .. }, _, _)252                | (ProjectionElem::Downcast { .. }, _, _)253                | (ProjectionElem::UnwrapUnsafeBinder(_), _, _) => {254                    // Recursive case. This can still be disjoint on a255                    // further iteration if this a shallow access and256                    // there's a deref later on, e.g., a borrow257                    // of `*x.y` while accessing `x`.258                }259            }260        }261    }262263    // Borrow path ran out but access path may not264    // have. Examples:265    //266    // - borrow of `a.b`, access to `a.b.c`267    // - borrow of `a.b`, access to `a.b`268    //269    // In the first example, where we didn't run out of270    // access, the borrow can access all of our place, so we271    // have a conflict.272    //273    // If the second example, where we did, then we still know274    // that the borrow can access a *part* of our place that275    // our access cares about, so we still have a conflict.276    if borrow_kind == BorrowKind::Fake(FakeBorrowKind::Shallow)277        && borrow_place.projection.len() < access_place.projection.len()278    {279        debug!("borrow_conflicts_with_place: shallow borrow");280        false281    } else {282        debug!("borrow_conflicts_with_place: full borrow, CONFLICT");283        true284    }285}286287// Given that the bases of `elem1` and `elem2` are always either equal288// or disjoint (and have the same type!), return the overlap situation289// between `elem1` and `elem2`.290fn place_projection_conflict<'tcx>(291    tcx: TyCtxt<'tcx>,292    body: &Body<'tcx>,293    pi1: PlaceRef<'tcx>,294    pi1_elem: PlaceElem<'tcx>,295    pi2_elem: PlaceElem<'tcx>,296    bias: PlaceConflictBias,297) -> Overlap {298    match (pi1_elem, pi2_elem) {299        (ProjectionElem::Deref, ProjectionElem::Deref) => {300            // derefs (e.g., `*x` vs. `*x`) - recur.301            debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");302            Overlap::EqualOrDisjoint303        }304        (ProjectionElem::OpaqueCast(_), ProjectionElem::OpaqueCast(_)) => {305            // casts to other types may always conflict irrespective of the type being cast to.306            debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE");307            Overlap::EqualOrDisjoint308        }309        (ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => {310            if f1 == f2 {311                // same field (e.g., `a.y` vs. `a.y`) - recur.312                debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");313                Overlap::EqualOrDisjoint314            } else {315                let ty = pi1.ty(body, tcx).ty;316                if ty.is_union() {317                    // Different fields of a union, we are basically stuck.318                    debug!("place_element_conflict: STUCK-UNION");319                    Overlap::Arbitrary320                } else {321                    // Different fields of a struct (`a.x` vs. `a.y`). Disjoint!322                    debug!("place_element_conflict: DISJOINT-FIELD");323                    Overlap::Disjoint324                }325            }326        }327        (ProjectionElem::Downcast(_, v1), ProjectionElem::Downcast(_, v2)) => {328            // different variants are treated as having disjoint fields,329            // even if they occupy the same "space", because it's330            // impossible for 2 variants of the same enum to exist331            // (and therefore, to be borrowed) at the same time.332            //333            // Note that this is different from unions - we *do* allow334            // this code to compile:335            //336            // ```337            // fn foo(x: &mut Result<i32, i32>) {338            //     let mut v = None;339            //     if let Ok(ref mut a) = *x {340            //         v = Some(a);341            //     }342            //     // here, you would *think* that the343            //     // *entirety* of `x` would be borrowed,344            //     // but in fact only the `Ok` variant is,345            //     // so the `Err` variant is *entirely free*:346            //     if let Err(ref mut a) = *x {347            //         v = Some(a);348            //     }349            //     drop(v);350            // }351            // ```352            if v1 == v2 {353                debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");354                Overlap::EqualOrDisjoint355            } else {356                debug!("place_element_conflict: DISJOINT-FIELD");357                Overlap::Disjoint358            }359        }360        (361            ProjectionElem::Index(..),362            ProjectionElem::Index(..)363            | ProjectionElem::ConstantIndex { .. }364            | ProjectionElem::Subslice { .. },365        )366        | (367            ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. },368            ProjectionElem::Index(..),369        ) => {370            // Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint371            // (if the indexes differ) or equal (if they are the same).372            match bias {373                PlaceConflictBias::Overlap => {374                    // If we are biased towards overlapping, then this is the recursive375                    // case that gives "equal *or* disjoint" its meaning.376                    debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX");377                    Overlap::EqualOrDisjoint378                }379                PlaceConflictBias::NoOverlap => {380                    // If we are biased towards no overlapping, then this is disjoint.381                    debug!("place_element_conflict: DISJOINT-ARRAY-INDEX");382                    Overlap::Disjoint383                }384            }385        }386        (387            ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: false },388            ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: false },389        )390        | (391            ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: true },392            ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: true },393        ) => {394            if o1 == o2 {395                debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX");396                Overlap::EqualOrDisjoint397            } else {398                debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX");399                Overlap::Disjoint400            }401        }402        (403            ProjectionElem::ConstantIndex {404                offset: offset_from_begin,405                min_length: min_length1,406                from_end: false,407            },408            ProjectionElem::ConstantIndex {409                offset: offset_from_end,410                min_length: min_length2,411                from_end: true,412            },413        )414        | (415            ProjectionElem::ConstantIndex {416                offset: offset_from_end,417                min_length: min_length1,418                from_end: true,419            },420            ProjectionElem::ConstantIndex {421                offset: offset_from_begin,422                min_length: min_length2,423                from_end: false,424            },425        ) => {426            // both patterns matched so it must be at least the greater of the two427            let min_length = max(min_length1, min_length2);428            // `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last429            // element (like -1 in Python) and `min_length` the first.430            // Therefore, `min_length - offset_from_end` gives the minimal possible431            // offset from the beginning432            if offset_from_begin >= min_length - offset_from_end {433                debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE");434                Overlap::EqualOrDisjoint435            } else {436                debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE");437                Overlap::Disjoint438            }439        }440        (441            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },442            ProjectionElem::Subslice { from, to, from_end: false },443        )444        | (445            ProjectionElem::Subslice { from, to, from_end: false },446            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },447        ) => {448            if (from..to).contains(&offset) {449                debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");450                Overlap::EqualOrDisjoint451            } else {452                debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE");453                Overlap::Disjoint454            }455        }456        (457            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },458            ProjectionElem::Subslice { from, .. },459        )460        | (461            ProjectionElem::Subslice { from, .. },462            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },463        ) => {464            if offset >= from {465                debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE");466                Overlap::EqualOrDisjoint467            } else {468                debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE");469                Overlap::Disjoint470            }471        }472        (473            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },474            ProjectionElem::Subslice { to, from_end: true, .. },475        )476        | (477            ProjectionElem::Subslice { to, from_end: true, .. },478            ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },479        ) => {480            if offset > to {481                debug!(482                    "place_element_conflict: \483                       DISJOINT-OR-EQ-SLICE-CONSTANT-INDEX-SUBSLICE-FE"484                );485                Overlap::EqualOrDisjoint486            } else {487                debug!("place_element_conflict: DISJOINT-SLICE-CONSTANT-INDEX-SUBSLICE-FE");488                Overlap::Disjoint489            }490        }491        (492            ProjectionElem::Subslice { from: f1, to: t1, from_end: false },493            ProjectionElem::Subslice { from: f2, to: t2, from_end: false },494        ) => {495            if f2 >= t1 || f1 >= t2 {496                debug!("place_element_conflict: DISJOINT-ARRAY-SUBSLICES");497                Overlap::Disjoint498            } else {499                debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");500                Overlap::EqualOrDisjoint501            }502        }503        (ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => {504            debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES");505            Overlap::EqualOrDisjoint506        }507        (508            ProjectionElem::Deref509            | ProjectionElem::Field(..)510            | ProjectionElem::Index(..)511            | ProjectionElem::ConstantIndex { .. }512            | ProjectionElem::OpaqueCast { .. }513            | ProjectionElem::Subslice { .. }514            | ProjectionElem::Downcast(..),515            _,516        ) => bug!(517            "mismatched projections in place_element_conflict: {:?} and {:?}",518            pi1_elem,519            pi2_elem520        ),521522        (ProjectionElem::UnwrapUnsafeBinder(_), _) => {523            todo!()524        }525    }526}

Code quality findings 16

Critical: Use of 'unsafe' keyword bypasses Rust's safety guarantees. Requires careful auditing, clear justification (FFI, specific optimizations), and minimal scope.
error safety unsafe-block
// report a conflict. This is unsafe code anyway so
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! BORROW: (*x1[2].y).z.a
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! ACCESS: (*x1[i].y).w.b
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ)
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! x1[2].y | x1[i].y -- equal or disjoint
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! *x1[2].y | *x1[i].y -- equal or disjoint
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! (*x1[2].y).z | (*x1[i].y).w -- we are disjoint and don't need to check more!
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! BORROW: (*x1[2].y).z.a
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! ACCESS: x1[i].y
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ)
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! x1[2].y | x1[i].y -- equal or disjoint
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
//! x1[2].y | (*x1[i].y) -- a deref! the access can't get past this, so we
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
/// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`.
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
// e.g., a (mutable) borrow of `a[5]` while we read the
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
// Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint
Maintainability Info: `todo!()` or `unimplemented!()` macros indicate incomplete code paths that will panic at runtime if reached. Ensure these are replaced with actual logic before production use.
info correctness todo-unimplemented
todo!()

Get this view in your editor

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