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

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


The following commit(s) were added to refs/heads/master by this push:
     new 3cc64b4f7c Fix incorrect unused coloring #5551
     new 137b7651eb Merge pull request #5670 from 
junichi11/php-gh-5551-incorrect-unused
3cc64b4f7c is described below

commit 3cc64b4f7c706ce5e4875b6e78deeb39da603817
Author: Junichi Yamamoto <junich...@apache.org>
AuthorDate: Fri Mar 17 11:24:11 2023 +0900

    Fix incorrect unused coloring #5551
    
    When there is an anonymous class in a method body, the anonymous class also 
removes method blocks of the enclosing class that need to be scanned.
    So, to prevent that, use `Map<TypeInfo, List<Block>>` instead of 
`List<Block>`
---
 .../modules/php/editor/csl/SemanticAnalysis.java   | 52 +++++++++++--------
 .../unit/data/testfiles/semantic/gh5551_01.php     | 51 +++++++++++++++++++
 .../data/testfiles/semantic/gh5551_01.php.semantic | 51 +++++++++++++++++++
 .../unit/data/testfiles/semantic/gh5551_02.php     | 59 ++++++++++++++++++++++
 .../data/testfiles/semantic/gh5551_02.php.semantic | 59 ++++++++++++++++++++++
 .../php/editor/csl/SemanticAnalyzerTest.java       |  8 +++
 6 files changed, 259 insertions(+), 21 deletions(-)

diff --git 
a/php/php.editor/src/org/netbeans/modules/php/editor/csl/SemanticAnalysis.java 
b/php/php.editor/src/org/netbeans/modules/php/editor/csl/SemanticAnalysis.java
index dbe9780708..a1aa52130c 100644
--- 
a/php/php.editor/src/org/netbeans/modules/php/editor/csl/SemanticAnalysis.java
+++ 
b/php/php.editor/src/org/netbeans/modules/php/editor/csl/SemanticAnalysis.java
@@ -227,7 +227,7 @@ public class SemanticAnalysis extends SemanticAnalyzer {
         // for unsed private method: name, identifier
         private final Map<UnusedIdentifier, ASTNodeColoring> 
privateUnusedMethods;
         // this is holder of blocks, which has to be scanned for usages in the 
class.
-        private List<Block> needToScan = new ArrayList<>();
+        private final Map<TypeInfo, List<Block>> needToScan = new HashMap<>();
 
         private final Snapshot snapshot;
 
@@ -409,18 +409,16 @@ public class SemanticAnalysis extends SemanticAnalyzer {
             scan(cldec.getInterfaes());
             Identifier name = cldec.getName();
             addColoringForNode(name, createTypeNameColoring(name));
-            needToScan = new ArrayList<>();
+            needToScan.put(typeInfo, new ArrayList<>());
             if (cldec.getBody() != null) {
                 cldec.getBody().accept(this);
 
                 // find all usages in the method bodies
-                while (!needToScan.isEmpty()) {
-                    Block block = needToScan.remove(0);
-                    block.accept(this);
-                }
+                scanMethodBodies();
                 addColoringForUnusedPrivateConstants();
                 addColoringForUnusedPrivateFields();
             }
+            needToScan.remove(typeInfo);
             removeFromPath();
         }
 
@@ -515,8 +513,8 @@ public class SemanticAnalysis extends SemanticAnalyzer {
                 // don't scan the body now. It should be scanned after all 
declarations
                 // are known
                 Block body = md.getFunction().getBody();
-                if (body != null) {
-                    needToScan.add(body);
+                if (body != null && needToScan.get(typeInfo) != null) {
+                    needToScan.get(typeInfo).add(body);
                 }
             }
         }
@@ -595,23 +593,24 @@ public class SemanticAnalysis extends SemanticAnalyzer {
                 // to avoid recognizing $this as an instance of an anonymous 
class
                 scan(node.ctorParams());
                 addToPath(node);
+                // GH-5551 keep original type info to scan parent blocks
+                TypeInfo originalTypeInfo = typeInfo;
                 typeInfo = new ClassInstanceCreationTypeInfo(node);
                 scan(node.getAttributes());
                 scan(node.getSuperClass());
                 scan(node.getInterfaces());
-                needToScan = new ArrayList<>();
+                needToScan.put(typeInfo, new ArrayList<>());
                 Block body = node.getBody();
                 if (body != null) {
                     body.accept(this);
 
                     // find all usages in the method bodies
-                    while (!needToScan.isEmpty()) {
-                        Block block = needToScan.remove(0);
-                        block.accept(this);
-                    }
+                    scanMethodBodies();
                     addColoringForUnusedPrivateConstants();
                     addColoringForUnusedPrivateFields();
                 }
+                needToScan.remove(typeInfo);
+                typeInfo = originalTypeInfo;
                 removeFromPath();
             } else {
                 super.visit(node);
@@ -639,14 +638,13 @@ public class SemanticAnalysis extends SemanticAnalyzer {
             typeInfo = new TypeDeclarationTypeInfo(node);
             Identifier name = node.getName();
             addColoringForNode(name, createTypeNameColoring(name));
-            needToScan = new ArrayList<>();
+            needToScan.put(typeInfo, new ArrayList<>());
             if (node.getBody() != null) {
                 node.getBody().accept(this);
-                for (Block block : needToScan) {
-                    block.accept(this);
-                }
+                scanMethodBodies();
                 addColoringForUnusedPrivateFields();
             }
+            needToScan.remove(typeInfo);
             removeFromPath();
         }
 
@@ -661,13 +659,12 @@ public class SemanticAnalysis extends SemanticAnalyzer {
             typeInfo = new TypeDeclarationTypeInfo(node);
             Identifier name = node.getName();
             addColoringForNode(name, createTypeNameColoring(name));
-            needToScan = new ArrayList<>();
+            needToScan.put(typeInfo, new ArrayList<>());
             if (node.getBody() != null) {
                 node.getBody().accept(this);
-                for (Block block : needToScan) {
-                    block.accept(this);
-                }
+                scanMethodBodies();
             }
+            needToScan.remove(typeInfo);
             removeFromPath();
         }
 
@@ -991,6 +988,19 @@ public class SemanticAnalysis extends SemanticAnalyzer {
             super.visit(node);
         }
 
+        /**
+         * Find all usages in the method bodies.
+         */
+        private void scanMethodBodies() {
+            if (needToScan.get(typeInfo) == null) {
+                return;
+            }
+            for (Block block : needToScan.get(typeInfo)) {
+                block.accept(this);
+            }
+            needToScan.get(typeInfo).clear();
+        }
+
         private class FieldAccessVisitor extends DefaultVisitor {
             private final Set<ColoringAttributes> coloring;
 
diff --git a/php/php.editor/test/unit/data/testfiles/semantic/gh5551_01.php 
b/php/php.editor/test/unit/data/testfiles/semantic/gh5551_01.php
new file mode 100644
index 0000000000..4c1256e5e3
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/semantic/gh5551_01.php
@@ -0,0 +1,51 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+class TestClass {
+    public function testMethod(string $test): string {
+        return $test;
+    }
+}
+
+interface TestInterface {
+    public function testMethod(string $test): string;
+}
+
+class GH5551 {
+
+    private function usedPrivateMethod1(): TestClass {
+        return new TestClass();
+    }
+
+    private function usedPrivateMethod2(): TestInterface {
+        return new class implements TestInterface {
+            public function testMethod(string $test): string {
+                return $test;
+            }
+        };
+    }
+
+    private function unusedPrivateMethod(): void {
+    }
+
+    public function test() {
+        echo $this->usedPrivateMethod1()->testMethod("test1"), PHP_EOL;
+        echo $this->usedPrivateMethod2()->testMethod("test2"), PHP_EOL;
+    }
+}
diff --git 
a/php/php.editor/test/unit/data/testfiles/semantic/gh5551_01.php.semantic 
b/php/php.editor/test/unit/data/testfiles/semantic/gh5551_01.php.semantic
new file mode 100644
index 0000000000..dbcdcefa6a
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/semantic/gh5551_01.php.semantic
@@ -0,0 +1,51 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+class |>CLASS:TestClass<| {
+    public function |>METHOD:testMethod<|(string $test): string {
+        return $test;
+    }
+}
+
+interface |>CLASS:TestInterface<| {
+    public function |>METHOD:testMethod<|(string $test): string;
+}
+
+class |>CLASS:GH5551<| {
+
+    private function |>METHOD:usedPrivateMethod1<|(): TestClass {
+        return new TestClass();
+    }
+
+    private function |>METHOD:usedPrivateMethod2<|(): TestInterface {
+        return new class implements TestInterface {
+            public function |>METHOD:testMethod<|(string $test): string {
+                return $test;
+            }
+        };
+    }
+
+    private function |>METHOD,UNUSED:unusedPrivateMethod<|(): void {
+    }
+
+    public function |>METHOD:test<|() {
+        echo 
$this->|>CUSTOM1:usedPrivateMethod1<|()->|>CUSTOM1:testMethod<|("test1"), 
PHP_EOL;
+        echo 
$this->|>CUSTOM1:usedPrivateMethod2<|()->|>CUSTOM1:testMethod<|("test2"), 
PHP_EOL;
+    }
+}
diff --git a/php/php.editor/test/unit/data/testfiles/semantic/gh5551_02.php 
b/php/php.editor/test/unit/data/testfiles/semantic/gh5551_02.php
new file mode 100644
index 0000000000..2d7f8cb0d0
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/semantic/gh5551_02.php
@@ -0,0 +1,59 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+class TestClass {
+    public function testMethod(string $test): string {
+        return $test;
+    }
+}
+
+interface TestInterface {
+    public function testMethod(string $test): string;
+}
+
+class GH5551 {
+
+    private function usedPrivateMethod1(): TestClass {
+        return new TestClass();
+    }
+
+    private function usedPrivateMethod2(): TestInterface {
+        return new class implements TestInterface {
+
+            private function unusedPrivateMethod(): void {
+            }
+
+            private function usedPrivateMethod(): void {
+            }
+
+            public function testMethod(string $test): string {
+                $this->usedPrivateMethod();
+                return $test;
+            }
+        };
+    }
+
+    private function unusedPrivateMethod(): void {
+    }
+
+    public function test() {
+        echo $this->usedPrivateMethod1()->testMethod("test1"), PHP_EOL;
+        echo $this->usedPrivateMethod2()->testMethod("test2"), PHP_EOL;
+    }
+}
diff --git 
a/php/php.editor/test/unit/data/testfiles/semantic/gh5551_02.php.semantic 
b/php/php.editor/test/unit/data/testfiles/semantic/gh5551_02.php.semantic
new file mode 100644
index 0000000000..870be797d9
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/semantic/gh5551_02.php.semantic
@@ -0,0 +1,59 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+class |>CLASS:TestClass<| {
+    public function |>METHOD:testMethod<|(string $test): string {
+        return $test;
+    }
+}
+
+interface |>CLASS:TestInterface<| {
+    public function |>METHOD:testMethod<|(string $test): string;
+}
+
+class |>CLASS:GH5551<| {
+
+    private function |>METHOD:usedPrivateMethod1<|(): TestClass {
+        return new TestClass();
+    }
+
+    private function |>METHOD:usedPrivateMethod2<|(): TestInterface {
+        return new class implements TestInterface {
+
+            private function |>METHOD,UNUSED:unusedPrivateMethod<|(): void {
+            }
+
+            private function |>METHOD:usedPrivateMethod<|(): void {
+            }
+
+            public function |>METHOD:testMethod<|(string $test): string {
+                $this->|>CUSTOM1:usedPrivateMethod<|();
+                return $test;
+            }
+        };
+    }
+
+    private function |>METHOD,UNUSED:unusedPrivateMethod<|(): void {
+    }
+
+    public function |>METHOD:test<|() {
+        echo 
$this->|>CUSTOM1:usedPrivateMethod1<|()->|>CUSTOM1:testMethod<|("test1"), 
PHP_EOL;
+        echo 
$this->|>CUSTOM1:usedPrivateMethod2<|()->|>CUSTOM1:testMethod<|("test2"), 
PHP_EOL;
+    }
+}
diff --git 
a/php/php.editor/test/unit/src/org/netbeans/modules/php/editor/csl/SemanticAnalyzerTest.java
 
b/php/php.editor/test/unit/src/org/netbeans/modules/php/editor/csl/SemanticAnalyzerTest.java
index 633e0221b8..f7c50a0cc9 100644
--- 
a/php/php.editor/test/unit/src/org/netbeans/modules/php/editor/csl/SemanticAnalyzerTest.java
+++ 
b/php/php.editor/test/unit/src/org/netbeans/modules/php/editor/csl/SemanticAnalyzerTest.java
@@ -217,4 +217,12 @@ public class SemanticAnalyzerTest extends 
SemanticAnalysisTestBase {
     public void testConstantsInTraits() throws Exception {
         checkSemantic("testfiles/semantic/constantsInTraits.php");
     }
+
+    public void testGH5551_01() throws Exception {
+        checkSemantic("testfiles/semantic/gh5551_01.php");
+    }
+
+    public void testGH5551_02() throws Exception {
+        checkSemantic("testfiles/semantic/gh5551_02.php");
+    }
 }


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

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

Reply via email to