You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by ne...@apache.org on 2023/01/23 16:46:11 UTC

[netbeans] branch delivery updated: Improved method checks in enum declaration

This is an automated email from the ASF dual-hosted git repository.

neilcsmith pushed a commit to branch delivery
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/delivery by this push:
     new 6b9c7a3a30a Improved method checks in enum declaration
     new ec3ab743f84 Merge pull request #5341 from KacerCZ/php-enum-check-methods
6b9c7a3a30a is described below

commit 6b9c7a3a30ad176856b5f8bfa6debeec129453d0
Author: Tomas Prochazka <ka...@razdva.cz>
AuthorDate: Sun Jan 22 13:11:33 2023 +0100

    Improved method checks in enum declaration
    
    - Checks declaration of forbidden methods.
    - Adds __invoke and __debugInfo to list of magic methods.
    
    Docs
    - https://www.php.net/manual/en/language.enumerations.listing.php
    - https://www.php.net/manual/en/class.backedenum.php
    - https://www.php.net/manual/en/language.enumerations.object-differences.php
    - https://www.php.net/manual/en/language.oop5.magic.php
    
    Closes #5086, closes #5094
---
 .../modules/php/editor/PredefinedSymbols.java      |  2 +
 .../verification/IncorrectEnumHintError.java       | 40 +++++++++-
 .../IncorrectEnumHintError/testIncorrectEnums.php  | 46 ++++++++++++
 ...testIncorrectEnums.php.testIncorrectEnums.hints | 87 ++++++++++++++++++++++
 4 files changed, 172 insertions(+), 3 deletions(-)

diff --git a/php/php.editor/src/org/netbeans/modules/php/editor/PredefinedSymbols.java b/php/php.editor/src/org/netbeans/modules/php/editor/PredefinedSymbols.java
index 006641fed3c..440bc9592d9 100644
--- a/php/php.editor/src/org/netbeans/modules/php/editor/PredefinedSymbols.java
+++ b/php/php.editor/src/org/netbeans/modules/php/editor/PredefinedSymbols.java
@@ -101,6 +101,8 @@ public final class PredefinedSymbols {
                 "__sleep", // NOI18N
                 "__wakeup", // NOI18N
                 "__toString", // NOI18N
+                "__invoke", // NOI18N
+                "__debugInfo", // NOI18N
                 "__serialize", // NOI18N PHP 7.4
                 "__unserialize", // NOI18N PHP 7.4
             })));
diff --git a/php/php.editor/src/org/netbeans/modules/php/editor/verification/IncorrectEnumHintError.java b/php/php.editor/src/org/netbeans/modules/php/editor/verification/IncorrectEnumHintError.java
index 1c0d10d3015..faa3dcf11ad 100644
--- a/php/php.editor/src/org/netbeans/modules/php/editor/verification/IncorrectEnumHintError.java
+++ b/php/php.editor/src/org/netbeans/modules/php/editor/verification/IncorrectEnumHintError.java
@@ -30,6 +30,7 @@ import org.netbeans.modules.csl.api.HintFix;
 import org.netbeans.modules.csl.api.OffsetRange;
 import org.netbeans.modules.csl.spi.support.CancelSupport;
 import org.netbeans.modules.php.editor.CodeUtils;
+import org.netbeans.modules.php.editor.PredefinedSymbols;
 import org.netbeans.modules.php.editor.model.EnumScope;
 import org.netbeans.modules.php.editor.model.FieldElement;
 import org.netbeans.modules.php.editor.model.FileScope;
@@ -57,8 +58,26 @@ import org.openide.util.NbBundle;
  */
 public class IncorrectEnumHintError extends HintErrorRule {
 
+    private static final Map<String, String> FORBIDDEN_MAGIC_METHODS = new HashMap<>();
+    private static final Map<String, String> FORBIDDEN_BACKED_ENUM_METHODS = new HashMap<>();
+
     private FileObject fileObject;
 
+    static {
+        for (String methodName : PredefinedSymbols.MAGIC_METHODS) {
+            // Methods __call, __callStatic and __invoke are allowed in enum.
+            if ("__call".equals(methodName) // NOI18N
+                    || "__callStatic".equals(methodName) // NOI18N
+                    || "__invoke".equals(methodName)) { // NOI18N
+                continue;
+            }
+            FORBIDDEN_MAGIC_METHODS.put(methodName.toLowerCase(), methodName);
+        }
+
+        FORBIDDEN_BACKED_ENUM_METHODS.put("from", "from"); // NOI18N
+        FORBIDDEN_BACKED_ENUM_METHODS.put("tryfrom", "tryFrom"); // NOI18N
+    }
+
     @Override
     @NbBundle.Messages("IncorrectEnumHintError.displayName=Incorrect Declaration of Enumeration")
     public String getDisplayName() {
@@ -73,7 +92,11 @@ public class IncorrectEnumHintError extends HintErrorRule {
         "# {0} - the trait name",
         "IncorrectEnumHintError.incorrectEnumPropertiesWithTrait=Enum cannot have properties, but \"{0}\" has properties",
         "IncorrectEnumHintError.incorrectEnumConstructor=Enum cannot have a constructor",
-    })
+        "IncorrectEnumHintError.incorrectEnumMethodCases=Enum cannot redeclare method \"cases\"",
+        "# {0} - the method name",
+        "IncorrectEnumHintError.incorrectEnumMagicMethod=Enum cannot contain magic method method \"{0}\"",
+        "# {0} - the method name",
+        "IncorrectEnumHintError.incorrectBackedEnumMethod=Backed enum cannot redeclare method \"{0}\"",})
     public void invoke(PHPRuleContext context, List<Hint> hints) {
         PHPParseResult phpParseResult = (PHPParseResult) context.parserResult;
         if (phpParseResult.getProgram() == null) {
@@ -113,7 +136,9 @@ public class IncorrectEnumHintError extends HintErrorRule {
                     return;
                 }
                 checkTraits(declaredEnum.getTraits(), declaredEnum, hints, checkVisitor.getUseTraits());
-                checkConstructor(declaredEnum.getDeclaredMethods(), hints);
+                // Forbidden methods from traits are ignored by PHP
+                boolean isBackedEnum = declaredEnum.getBackingType() != null;
+                checkMethods(declaredEnum.getDeclaredMethods(), isBackedEnum, hints);
             }
         }
     }
@@ -142,13 +167,22 @@ public class IncorrectEnumHintError extends HintErrorRule {
         }
     }
 
-    private void checkConstructor(Collection<? extends MethodScope> methods, List<Hint> hints) {
+    private void checkMethods(Collection<? extends MethodScope> methods, boolean isBackedEnum, List<Hint> hints) {
         for (MethodScope method : methods) {
             if (CancelSupport.getDefault().isCancelled()) {
                 return;
             }
             if (method.isConstructor()) {
                 addHint(method, Bundle.IncorrectEnumHintError_incorrectEnumConstructor(), hints);
+                continue;
+            }
+            String methodName = method.getName().toLowerCase();
+            if ("cases".equals(methodName)) { // NOI18N
+                addHint(method, Bundle.IncorrectEnumHintError_incorrectEnumMethodCases(), hints);
+            } else if (FORBIDDEN_MAGIC_METHODS.containsKey(methodName)) {
+                addHint(method, Bundle.IncorrectEnumHintError_incorrectEnumMagicMethod(FORBIDDEN_MAGIC_METHODS.get(methodName)), hints);
+            } else if (isBackedEnum && FORBIDDEN_BACKED_ENUM_METHODS.containsKey(methodName)) {
+                addHint(method, Bundle.IncorrectEnumHintError_incorrectBackedEnumMethod(FORBIDDEN_BACKED_ENUM_METHODS.get(methodName)), hints);
             }
         }
     }
diff --git a/php/php.editor/test/unit/data/testfiles/verification/IncorrectEnumHintError/testIncorrectEnums.php b/php/php.editor/test/unit/data/testfiles/verification/IncorrectEnumHintError/testIncorrectEnums.php
index 1c87b7710a5..67bb8b04d25 100644
--- a/php/php.editor/test/unit/data/testfiles/verification/IncorrectEnumHintError/testIncorrectEnums.php
+++ b/php/php.editor/test/unit/data/testfiles/verification/IncorrectEnumHintError/testIncorrectEnums.php
@@ -40,6 +40,52 @@ enum IncorrectConstructor {
     }
 }
 
+enum IncorrectMethods {
+    public function cases():array {}
+    public function __get($name) {}
+    public function __set($name,$value) {}
+    public function __isset($name) {}
+    public function __unset($name) {}
+    public function __sleep() {}
+    public function __wakeup() {}
+    public function __serialize() {}
+    public function __unserialize($array) {}
+    public function __toString() {}
+    public static function __set_state($state) {}
+    public function __clone() {}
+    public function __debugInfo() {}
+}
+
+enum IncorrectMethodsBacked: string {
+    public function cases():array {}
+    public function from(string|int $value):self {}
+    public function tryFrom(string|int $value):self {}
+}
+
+enum IncorrectMethodsCorrectCaseInMessage {
+    public function Cases():array {}
+    public function __GET($name) {}
+    public function __seT($name,$value) {}
+    public function __ISset($name) {}
+    public function __unSET($name) {}
+    public function __sleeP() {}
+    public function __wAkeup() {}
+    public function __Serialize() {}
+    public function __Unserialize($array) {}
+    public function __ToString() {}
+    public static function __Set_State($state) {}
+    public function __clONe() {}
+    public function __DebugInfo() {}
+}
+
+enum CorrectMethods {
+    public function from(string|int $value):self {}
+    public function tryFrom(string|int $value):self {}
+    public function __call($name,$args) {}
+    public static function __callStatic($name,$args) {}
+    public function __invoke() {}
+}
+
 enum CorrectBackingTypeString: string {
     case CASE_NAME;
 }
diff --git a/php/php.editor/test/unit/data/testfiles/verification/IncorrectEnumHintError/testIncorrectEnums.php.testIncorrectEnums.hints b/php/php.editor/test/unit/data/testfiles/verification/IncorrectEnumHintError/testIncorrectEnums.php.testIncorrectEnums.hints
index 3ead2c1f278..36c0309db3a 100644
--- a/php/php.editor/test/unit/data/testfiles/verification/IncorrectEnumHintError/testIncorrectEnums.php.testIncorrectEnums.hints
+++ b/php/php.editor/test/unit/data/testfiles/verification/IncorrectEnumHintError/testIncorrectEnums.php.testIncorrectEnums.hints
@@ -20,6 +20,93 @@ HINT:Enum cannot have properties
     public function __construct() {
                     -----------
 HINT:Enum cannot have a constructor
+    public function cases():array {}
+                    -----
+HINT:Enum cannot redeclare method "cases"
+    public function __get($name) {}
+                    -----
+HINT:Enum cannot contain magic method method "__get"
+    public function __set($name,$value) {}
+                    -----
+HINT:Enum cannot contain magic method method "__set"
+    public function __isset($name) {}
+                    -------
+HINT:Enum cannot contain magic method method "__isset"
+    public function __unset($name) {}
+                    -------
+HINT:Enum cannot contain magic method method "__unset"
+    public function __sleep() {}
+                    -------
+HINT:Enum cannot contain magic method method "__sleep"
+    public function __wakeup() {}
+                    --------
+HINT:Enum cannot contain magic method method "__wakeup"
+    public function __serialize() {}
+                    -----------
+HINT:Enum cannot contain magic method method "__serialize"
+    public function __unserialize($array) {}
+                    -------------
+HINT:Enum cannot contain magic method method "__unserialize"
+    public function __toString() {}
+                    ----------
+HINT:Enum cannot contain magic method method "__toString"
+    public static function __set_state($state) {}
+                           -----------
+HINT:Enum cannot contain magic method method "__set_state"
+    public function __clone() {}
+                    -------
+HINT:Enum cannot contain magic method method "__clone"
+    public function __debugInfo() {}
+                    -----------
+HINT:Enum cannot contain magic method method "__debugInfo"
+    public function cases():array {}
+                    -----
+HINT:Enum cannot redeclare method "cases"
+    public function from(string|int $value):self {}
+                    ----
+HINT:Backed enum cannot redeclare method "from"
+    public function tryFrom(string|int $value):self {}
+                    -------
+HINT:Backed enum cannot redeclare method "tryFrom"
+    public function Cases():array {}
+                    -----
+HINT:Enum cannot redeclare method "cases"
+    public function __GET($name) {}
+                    -----
+HINT:Enum cannot contain magic method method "__get"
+    public function __seT($name,$value) {}
+                    -----
+HINT:Enum cannot contain magic method method "__set"
+    public function __ISset($name) {}
+                    -------
+HINT:Enum cannot contain magic method method "__isset"
+    public function __unSET($name) {}
+                    -------
+HINT:Enum cannot contain magic method method "__unset"
+    public function __sleeP() {}
+                    -------
+HINT:Enum cannot contain magic method method "__sleep"
+    public function __wAkeup() {}
+                    --------
+HINT:Enum cannot contain magic method method "__wakeup"
+    public function __Serialize() {}
+                    -----------
+HINT:Enum cannot contain magic method method "__serialize"
+    public function __Unserialize($array) {}
+                    -------------
+HINT:Enum cannot contain magic method method "__unserialize"
+    public function __ToString() {}
+                    ----------
+HINT:Enum cannot contain magic method method "__toString"
+    public static function __Set_State($state) {}
+                           -----------
+HINT:Enum cannot contain magic method method "__set_state"
+    public function __clONe() {}
+                    -------
+HINT:Enum cannot contain magic method method "__clone"
+    public function __DebugInfo() {}
+                    -----------
+HINT:Enum cannot contain magic method method "__debugInfo"
     case C;
     -------
 HINT:"case" can only be in enums


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists