Skip to main content

mago_analyzer/plugin/libraries/stdlib/json/
json_encode.rs

1//! `json_encode()` return type provider.
2
3use mago_codex::ttype::atomic::TAtomic;
4use mago_codex::ttype::atomic::scalar::TScalar;
5use mago_codex::ttype::atomic::scalar::bool::TBool;
6use mago_codex::ttype::atomic::scalar::string::TString;
7use mago_codex::ttype::get_non_empty_string;
8use mago_codex::ttype::union::TUnion;
9
10use crate::plugin::context::InvocationInfo;
11use crate::plugin::context::ProviderContext;
12use crate::plugin::provider::Provider;
13use crate::plugin::provider::ProviderMeta;
14use crate::plugin::provider::function::FunctionReturnTypeProvider;
15use crate::plugin::provider::function::FunctionTarget;
16
17const JSON_THROW_ON_ERROR: i64 = 4_194_304;
18
19static META: ProviderMeta = ProviderMeta::new(
20    "php::json::json_encode",
21    "json_encode",
22    "Returns non-empty-string when JSON_THROW_ON_ERROR is set, otherwise string|false",
23);
24
25/// Provider for the `json_encode()` function.
26///
27/// When `JSON_THROW_ON_ERROR` flag is set, returns `non-empty-string`.
28/// Otherwise returns `non-empty-string|false`.
29#[derive(Default)]
30pub struct JsonEncodeProvider;
31
32impl Provider for JsonEncodeProvider {
33    fn meta() -> &'static ProviderMeta {
34        &META
35    }
36}
37
38impl FunctionReturnTypeProvider for JsonEncodeProvider {
39    fn targets() -> FunctionTarget {
40        FunctionTarget::Exact("json_encode")
41    }
42
43    fn get_return_type(
44        &self,
45        context: &ProviderContext<'_, '_, '_>,
46        invocation: &InvocationInfo<'_, '_, '_>,
47    ) -> Option<TUnion> {
48        let flags_argument = invocation.get_argument(1, &["flags"])?;
49        let flags_type = context.get_expression_type(flags_argument)?;
50        let flags_value = flags_type.get_single_literal_int_value()?;
51
52        Some(if flags_value & JSON_THROW_ON_ERROR > 0 {
53            get_non_empty_string()
54        } else {
55            TUnion::from_vec(vec![
56                TAtomic::Scalar(TScalar::String(TString::non_empty())),
57                TAtomic::Scalar(TScalar::Bool(TBool::r#false())),
58            ])
59        })
60    }
61}