diff --git a/crates/linter/src/plugin/compatibility/mod.rs b/crates/linter/src/plugin/compatibility/mod.rs index 6e71f03e..5ad779d1 100644 --- a/crates/linter/src/plugin/compatibility/mod.rs +++ b/crates/linter/src/plugin/compatibility/mod.rs @@ -1,4 +1,6 @@ use crate::definition::PluginDefinition; +use crate::plugin::compatibility::rules::php55::finally_feature::FinallyFeatureRule; +use crate::plugin::compatibility::rules::php56::variadic_functions_feature::VariadicFunctionsFeatureRule; use crate::plugin::compatibility::rules::php74::null_coalesce_assignment_feature::NullCoalesceAssignmentFeatureRule; use crate::plugin::compatibility::rules::php80::named_arguments_feature::NamedArgumentsFeatureRule; use crate::plugin::compatibility::rules::php80::promoted_properties_feature::PromotedPropertiesFeatureRule; @@ -25,6 +27,10 @@ impl Plugin for CompatibilityPlugin { fn get_rules(&self) -> Vec> { vec![ + // PHP 5.5 + Box::new(FinallyFeatureRule), + // PHP 5.6 + Box::new(VariadicFunctionsFeatureRule), // PHP 7.4 Box::new(NullCoalesceAssignmentFeatureRule), // PHP 8.0 diff --git a/crates/linter/src/plugin/compatibility/rules/mod.rs b/crates/linter/src/plugin/compatibility/rules/mod.rs index 3725fb71..f74ab52b 100644 --- a/crates/linter/src/plugin/compatibility/rules/mod.rs +++ b/crates/linter/src/plugin/compatibility/rules/mod.rs @@ -1,3 +1,11 @@ +pub mod php55 { + pub mod finally_feature; +} + +pub mod php56 { + pub mod variadic_functions_feature; +} + pub mod php74 { pub mod null_coalesce_assignment_feature; } diff --git a/crates/linter/src/plugin/compatibility/rules/php55/finally_feature.rs b/crates/linter/src/plugin/compatibility/rules/php55/finally_feature.rs new file mode 100644 index 00000000..26ba0214 --- /dev/null +++ b/crates/linter/src/plugin/compatibility/rules/php55/finally_feature.rs @@ -0,0 +1,71 @@ +use indoc::indoc; + +use mago_ast::ast::*; +use mago_php_version::PHPVersion; +use mago_reporting::*; +use mago_span::*; +use mago_walker::Walker; + +use crate::context::LintContext; +use crate::definition::RuleDefinition; +use crate::definition::RuleUsageExample; +use crate::rule::Rule; + +#[derive(Clone, Copy, Debug)] +pub struct FinallyFeatureRule; + +impl Rule for FinallyFeatureRule { + fn get_definition(&self) -> RuleDefinition { + RuleDefinition::enabled("Finally Feature", Level::Error) + .with_maximum_supported_php_version(PHPVersion::PHP54) + .with_description(indoc! {" + Flags any usage of the `finally` keyword, which was introduced in PHP 5.5. + + In environments running older versions of PHP, you can use a `try`/`catch` block without a `finally` block instead. + "}) + .with_example(RuleUsageExample::valid( + "Using a `try`/`catch` block without a `finally` block", + indoc! {r#" + Walker> for FinallyFeatureRule { + fn walk_in_try<'ast>(&self, r#try: &'ast Try, context: &mut LintContext<'a>) { + let Some(finally) = r#try.finally_clause.as_ref() else { + return; + }; + + let issue = Issue::new( + context.level(), + "The `finally` block is only available in PHP 5.5 and later.", + ) + .with_annotation( + Annotation::primary(finally.span()).with_message("Finally block used here."), + ); + + context.report(issue); + } +} diff --git a/crates/linter/src/plugin/compatibility/rules/php56/variadic_functions_feature.rs b/crates/linter/src/plugin/compatibility/rules/php56/variadic_functions_feature.rs new file mode 100644 index 00000000..eb375a64 --- /dev/null +++ b/crates/linter/src/plugin/compatibility/rules/php56/variadic_functions_feature.rs @@ -0,0 +1,73 @@ +use indoc::indoc; + +use mago_ast::ast::*; +use mago_php_version::PHPVersion; +use mago_reporting::*; +use mago_span::*; +use mago_walker::Walker; + +use crate::context::LintContext; +use crate::definition::RuleDefinition; +use crate::definition::RuleUsageExample; +use crate::rule::Rule; + +#[derive(Clone, Copy, Debug)] +pub struct VariadicFunctionsFeatureRule; + +impl Rule for VariadicFunctionsFeatureRule { + fn get_definition(&self) -> RuleDefinition { + RuleDefinition::enabled("Variadic Functions Feature", Level::Error) + .with_maximum_supported_php_version(PHPVersion::PHP55) + .with_description(indoc! {" + Flags any usage of variadic functions, which were introduced in PHP 5.6. + + In environments running older versions of PHP, you can use the `func_get_args()` function instead. + "}) + .with_example(RuleUsageExample::valid( + "Using `func_get_args()` instead of variadic functions", + indoc! {r#" + Walker> for VariadicFunctionsFeatureRule { + fn walk_in_function<'ast>(&self, function: &'ast Function, context: &mut LintContext<'a>) { + for param in function.parameters.parameters.iter() { + if param.ellipsis.is_none() { + continue; + } + + let issue = Issue::new( + context.level(), + "Variadic functions are only available in PHP 5.6 and later.", + ) + .with_annotation( + Annotation::primary(param.span()).with_message("Variadic parameter used here."), + ) + .with_note("Use `func_get_args()` if you need compatibility with older PHP versions."); + + context.report(issue); + } + } +} diff --git a/crates/php-version/src/lib.rs b/crates/php-version/src/lib.rs index db23a17e..9cb78d7d 100644 --- a/crates/php-version/src/lib.rs +++ b/crates/php-version/src/lib.rs @@ -31,6 +31,12 @@ pub mod feature; pub struct PHPVersion(u32); impl PHPVersion { + /// The PHP 5.4 version. + pub const PHP54: PHPVersion = PHPVersion::new(5, 4, 0); + + /// The PHP 5.5 version. + pub const PHP55: PHPVersion = PHPVersion::new(5, 5, 0); + /// The PHP 7.0 version. pub const PHP70: PHPVersion = PHPVersion::new(7, 0, 0); diff --git a/src/consts.rs b/src/consts.rs index b9720e79..ec6add7e 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -49,7 +49,7 @@ pub const MAXIMUM_STACK_SIZE: usize = 256 * 1024 * 1024; pub const DEFAULT_PHP_VERSION: PHPVersion = PHPVersion::PHP83; /// The minimum supported PHP version. -pub const MINIMUM_PHP_VERSION: PHPVersion = PHPVersion::PHP74; +pub const MINIMUM_PHP_VERSION: PHPVersion = PHPVersion::PHP54; /// The maximum supported PHP version. pub const MAXIMUM_PHP_VERSION: PHPVersion = PHPVersion::PHP84;