mago_analyzer/plugin/libraries/stdlib/json/
json_encode.rs1use 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#[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}