Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T03:28:46.747Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

owned_string_into_shared.rs

172 lines · 5.6 KB · rust
1use clippy_utils::diagnostics::span_lint;
2use rustc_ast::ast::LitKind;
3use rustc_hir::def::{DefKind, Res};
4use rustc_hir::{Expr, ExprKind};
5use rustc_lint::{LateContext, LateLintPass};
6use rustc_middle::ty::Ty;
7
8rustc_session::declare_lint! {
9    /// ### What it does
10    ///
11    /// Flags expressions that build an owned `String` from a string literal
12    /// and then immediately convert it with `.into()` into one of the
13    /// refcounted/shared string types: `gpui::SharedString`, `Arc<str>`,
14    /// `Rc<str>`, or `Cow<'_, str>`.
15    ///
16    /// The flagged shapes are:
17    ///
18    /// ```ignore
19    /// let label: SharedString = String::from("foo").into();
20    /// let key:   Arc<str>     = "foo".to_string().into();
21    /// let value: Rc<str>      = "foo".to_owned().into();
22    /// ```
23    ///
24    /// ### Why is this bad?
25    ///
26    /// Two heap allocations and two copies of the literal happen where one is
27    /// enough: `String::from` (or `to_string`/`to_owned`) allocates a `String`
28    /// and copies the bytes; the `.into()` conversion into the refcounted
29    /// destination then allocates an `Arc<str>`-like buffer and copies the
30    /// bytes a second time. For string literals the destination can be built
31    /// directly from `'static` data with no allocation at all.
32    pub OWNED_STRING_INTO_SHARED,
33    Warn,
34    "an owned `String` is built from a string literal only to be converted into a refcounted string"
35}
36
37pub(crate) struct OwnedStringIntoShared;
38
39rustc_session::impl_lint_pass!(OwnedStringIntoShared => [OWNED_STRING_INTO_SHARED]);
40
41impl<'tcx> LateLintPass<'tcx> for OwnedStringIntoShared {
42    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
43        if expr.span.from_expansion() {
44            return;
45        }
46
47        let ExprKind::MethodCall(segment, receiver, [], _) = &expr.kind else {
48            return;
49        };
50        if segment.ident.name.as_str() != "into" {
51            return;
52        }
53
54        let dest_ty = cx.typeck_results().expr_ty(expr);
55        if !is_refcounted_string_destination(cx, dest_ty) {
56            return;
57        }
58
59        // The receiver must produce an owned `String`. Confirming this rules
60        // out custom `into` impls on unrelated types that just happen to look
61        // similar.
62        let receiver_ty = cx.typeck_results().expr_ty(receiver);
63        if !is_std_string(cx, receiver_ty) {
64            return;
65        }
66
67        if !is_owned_string_built_from_literal(cx, receiver) {
68            return;
69        }
70
71        span_lint(
72            cx,
73            OWNED_STRING_INTO_SHARED,
74            expr.span,
75            "this allocates an owned `String` from a string literal only to convert it into a refcounted string",
76        );
77    }
78}
79
80/// Returns `true` when `ty` is one of the refcounted/shared string types this
81/// lint targets: `gpui::SharedString`, `Arc<str>`, `Rc<str>`, or
82/// `Cow<'_, str>`.
83fn is_refcounted_string_destination<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
84    let Some(adt) = ty.ty_adt_def() else {
85        return false;
86    };
87    let did = adt.did();
88
89    if cx.tcx.crate_name(did.krate).as_str() == "gpui_shared_string"
90        && cx.tcx.item_name(did).as_str() == "SharedString"
91    {
92        return true;
93    }
94
95    let path = cx.tcx.def_path_str(did);
96    let is_str_wrapper = matches!(
97        path.as_str(),
98        "alloc::sync::Arc"
99            | "std::sync::Arc"
100            | "alloc::rc::Rc"
101            | "std::rc::Rc"
102            | "alloc::borrow::Cow"
103            | "std::borrow::Cow"
104    );
105    if !is_str_wrapper {
106        return false;
107    }
108
109    let rustc_middle::ty::TyKind::Adt(_, args) = ty.kind() else {
110        return false;
111    };
112    args.iter()
113        .find_map(|arg| arg.as_type())
114        .is_some_and(|inner| inner.is_str())
115}
116
117/// Returns `true` when `ty` is `alloc::string::String`.
118fn is_std_string(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
119    let Some(adt) = ty.ty_adt_def() else {
120        return false;
121    };
122    let path = cx.tcx.def_path_str(adt.did());
123    path == "alloc::string::String" || path == "std::string::String"
124}
125
126/// Returns `true` if `expr` matches one of:
127///
128/// * `String::from(<string literal>)`
129/// * `<string literal>.to_string()`
130/// * `<string literal>.to_owned()`
131fn is_owned_string_built_from_literal<'tcx>(
132    cx: &LateContext<'tcx>,
133    expr: &'tcx Expr<'tcx>,
134) -> bool {
135    match &expr.kind {
136        ExprKind::Call(func, [arg]) => {
137            let ExprKind::Path(qpath) = &func.kind else {
138                return false;
139            };
140            let Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) = cx.qpath_res(qpath, func.hir_id)
141            else {
142                return false;
143            };
144            if cx.tcx.item_name(def_id).as_str() != "from" {
145                return false;
146            }
147            is_string_literal(arg)
148        }
149        ExprKind::MethodCall(segment, receiver, [], _) => {
150            let name = segment.ident.name.as_str();
151            if name != "to_string" && name != "to_owned" {
152                return false;
153            }
154            is_string_literal(receiver)
155        }
156        _ => false,
157    }
158}
159
160/// Returns `true` if `expr` is a string-literal expression, optionally wrapped
161/// in a single layer of reference (`&"lit"`).
162fn is_string_literal<'tcx>(expr: &'tcx Expr<'tcx>) -> bool {
163    let inner = match &expr.kind {
164        ExprKind::AddrOf(_, _, inner) => *inner,
165        _ => expr,
166    };
167    matches!(
168        &inner.kind,
169        ExprKind::Lit(lit) if matches!(lit.node, LitKind::Str(..))
170    )
171}
172
Served at tenant.openagents/omega Member data and write actions are omitted.