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

matthiasblaesing 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 5f33fe47b1 Fix handling of classes declared in anonymous functions
     new 4e6930488c Merge pull request #6249 from matthiasblaesing/js_fixes
5f33fe47b1 is described below

commit 5f33fe47b1e127eefaf86dcc2aa96d3a2b644096
Author: Matthias Bläsing <[email protected]>
AuthorDate: Sun Jul 23 20:46:52 2023 +0200

    Fix handling of classes declared in anonymous functions
    
    Consider this construct:
    
      (function () {
          class Directory {
              constructor(displayName) {
                  this.displayName = displayName;
              }
          }
    
          class ImageFile{
              constructor(displayName){
                this.displayName = displayName;
              }
          }
      })();
    
    Before this change this construct was not correctly parsed and the
    constructor was not cleanly recognised, leading to missing usage
    marks (i.e. the displayName above was marked as unused).
    
    A different fallout of that problem is visible with this:
    
      (function () {
          class Directory {
              constructor(displayName) {
                  this.displayName = displayName;
              }
          }
    
          class ImageFile{
              constructor(displayName){
                  this.displayName = displayName;
              }
          }
    
          function getJsonData(folderURL) {
              const body = folderURL;
          }
      })();
    
    Problems:
    
    - constructor from ImageFile is shown as a toplevel function
    - ImageFile is listed without its constructor and without its
      displayName property
---
 .../structure/classInAnonymousFunction.js          | 33 +++++++++++++++++++
 .../classInAnonymousFunction.js.structure          |  6 ++++
 .../structure/classInAnonymousFunction2.js         | 36 +++++++++++++++++++++
 .../classInAnonymousFunction2.js.structure         |  7 ++++
 .../javascript2/editor/JsStructureScannerTest.java |  8 +++++
 .../modules/javascript2/model/ModelVisitor.java    | 21 +++++++++---
 .../testfiles/model/classInAnonymousFunction.js    | 33 +++++++++++++++++++
 .../model/classInAnonymousFunction.js.model        | 29 +++++++++++++++++
 .../testfiles/model/classInAnonymousFunction2.js   | 36 +++++++++++++++++++++
 .../model/classInAnonymousFunction2.js.model       | 37 ++++++++++++++++++++++
 .../modules/javascript2/model/ModelTest.java       |  8 +++++
 11 files changed, 249 insertions(+), 5 deletions(-)

diff --git 
a/webcommon/javascript2.editor/test/unit/data/testfiles/structure/classInAnonymousFunction.js
 
b/webcommon/javascript2.editor/test/unit/data/testfiles/structure/classInAnonymousFunction.js
new file mode 100644
index 0000000000..2d05a5fb09
--- /dev/null
+++ 
b/webcommon/javascript2.editor/test/unit/data/testfiles/structure/classInAnonymousFunction.js
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+(function () {
+
+    class Directory {
+        constructor(displayName) {
+            this.displayName = displayName;
+        }
+    }
+
+    class ImageFile{
+        constructor(displayName){
+            this.displayName = displayName;
+        }
+    }
+})();
diff --git 
a/webcommon/javascript2.editor/test/unit/data/testfiles/structure/classInAnonymousFunction.js.structure
 
b/webcommon/javascript2.editor/test/unit/data/testfiles/structure/classInAnonymousFunction.js.structure
new file mode 100644
index 0000000000..0ab97d2a39
--- /dev/null
+++ 
b/webcommon/javascript2.editor/test/unit/data/testfiles/structure/classInAnonymousFunction.js.structure
@@ -0,0 +1,6 @@
+Directory:CLASS:[PUBLIC]:ESCAPED{Directory}:
+  
constructor:CONSTRUCTOR:[PUBLIC]:ESCAPED{constructor}ESCAPED{(}ESCAPED{displayName}ESCAPED{)}<font
 color="#999999">ESCAPED{ : }Directory</font>:
+  displayName:FIELD:[PUBLIC]:ESCAPED{displayName}:
+ImageFile:CLASS:[PUBLIC]:ESCAPED{ImageFile}:
+  
constructor:CONSTRUCTOR:[PUBLIC]:ESCAPED{constructor}ESCAPED{(}ESCAPED{displayName}ESCAPED{)}<font
 color="#999999">ESCAPED{ : }ImageFile</font>:
+  displayName:FIELD:[PUBLIC]:ESCAPED{displayName}:
diff --git 
a/webcommon/javascript2.editor/test/unit/data/testfiles/structure/classInAnonymousFunction2.js
 
b/webcommon/javascript2.editor/test/unit/data/testfiles/structure/classInAnonymousFunction2.js
new file mode 100644
index 0000000000..64c9739527
--- /dev/null
+++ 
b/webcommon/javascript2.editor/test/unit/data/testfiles/structure/classInAnonymousFunction2.js
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+(function () {
+    class Directory {
+        constructor(displayName) {
+            this.displayName = displayName;
+        }
+    }
+
+    class ImageFile{
+        constructor(displayName){
+            this.displayName = displayName;
+        }
+    }
+
+    function getJsonData(folderURL) {
+        const body = folderURL;
+    }
+})();
\ No newline at end of file
diff --git 
a/webcommon/javascript2.editor/test/unit/data/testfiles/structure/classInAnonymousFunction2.js.structure
 
b/webcommon/javascript2.editor/test/unit/data/testfiles/structure/classInAnonymousFunction2.js.structure
new file mode 100644
index 0000000000..a9b0cc53e3
--- /dev/null
+++ 
b/webcommon/javascript2.editor/test/unit/data/testfiles/structure/classInAnonymousFunction2.js.structure
@@ -0,0 +1,7 @@
+Directory:CLASS:[PUBLIC]:ESCAPED{Directory}:
+  
constructor:CONSTRUCTOR:[PUBLIC]:ESCAPED{constructor}ESCAPED{(}ESCAPED{displayName}ESCAPED{)}<font
 color="#999999">ESCAPED{ : }Directory</font>:
+  displayName:FIELD:[PUBLIC]:ESCAPED{displayName}:
+ImageFile:CLASS:[PUBLIC]:ESCAPED{ImageFile}:
+  
constructor:CONSTRUCTOR:[PUBLIC]:ESCAPED{constructor}ESCAPED{(}ESCAPED{displayName}ESCAPED{)}<font
 color="#999999">ESCAPED{ : }ImageFile</font>:
+  displayName:FIELD:[PUBLIC]:ESCAPED{displayName}:
+getJsonData:METHOD:[PRIVATE]:ESCAPED{getJsonData}ESCAPED{(}ESCAPED{folderURL}ESCAPED{)}<font
 color="#999999">ESCAPED{ : }undefined</font>:
diff --git 
a/webcommon/javascript2.editor/test/unit/src/org/netbeans/modules/javascript2/editor/JsStructureScannerTest.java
 
b/webcommon/javascript2.editor/test/unit/src/org/netbeans/modules/javascript2/editor/JsStructureScannerTest.java
index 5073a1edc3..205f858ef5 100644
--- 
a/webcommon/javascript2.editor/test/unit/src/org/netbeans/modules/javascript2/editor/JsStructureScannerTest.java
+++ 
b/webcommon/javascript2.editor/test/unit/src/org/netbeans/modules/javascript2/editor/JsStructureScannerTest.java
@@ -766,4 +766,12 @@ public class JsStructureScannerTest extends JsTestBase {
     public void testObjectNameMatchingNestedFunction() throws Exception {
         
checkStructure("testfiles/structure/objectNameMatchingNestedFunction.js");
     }
+
+    public void testClassInAnonymousFunction() throws Exception {
+        checkStructure("testfiles/structure/classInAnonymousFunction.js");
+    }
+
+    public void testClassInAnonymousFunction2() throws Exception {
+        checkStructure("testfiles/structure/classInAnonymousFunction2.js");
+    }
 }
diff --git 
a/webcommon/javascript2.model/src/org/netbeans/modules/javascript2/model/ModelVisitor.java
 
b/webcommon/javascript2.model/src/org/netbeans/modules/javascript2/model/ModelVisitor.java
index aeeb25e8df..752c09985e 100644
--- 
a/webcommon/javascript2.model/src/org/netbeans/modules/javascript2/model/ModelVisitor.java
+++ 
b/webcommon/javascript2.model/src/org/netbeans/modules/javascript2/model/ModelVisitor.java
@@ -62,10 +62,10 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
 import java.util.Stack;
 import java.util.logging.Level;
@@ -2479,6 +2479,12 @@ public class ModelVisitor extends PathNodeVisitor 
implements ModelResolver {
         return super.enterUnaryNode(unaryNode);
     }
 
+    // Track objects pushed to ModelBuilder from VarNode handling. objects are
+    // only conditionally pushed enterVarNode and thus leaveVarNode must only
+    // pop that state if it came from enterVarNode. There should be a better
+    // solution, but should be ok in the interim
+    private final Map<JsObject, VarNode> varNodeScopes = new 
IdentityHashMap<>();
+
     @Override
     public boolean enterVarNode(VarNode varNode) {
         Node init = varNode.getInit();
@@ -2522,10 +2528,10 @@ public class ModelVisitor extends PathNodeVisitor 
implements ModelResolver {
 //            }
 
         }
-         if (!(init instanceof ObjectNode || rNode != null
-                 || init instanceof LiteralNode.ArrayLiteralNode
-                 || init instanceof ClassNode
-                 || varNode.isExport())) {
+        if (!(init instanceof ObjectNode || rNode != null
+                || init instanceof LiteralNode.ArrayLiteralNode
+                || init instanceof ClassNode
+                || varNode.isExport())) {
             JsObject parent = modelBuilder.getCurrentObject();
             //parent = canBeSingletonPattern(1) ? resolveThis(parent) : parent;
             if (parent instanceof CatchBlockImpl) {
@@ -2605,6 +2611,7 @@ public class ModelVisitor extends PathNodeVisitor 
implements ModelResolver {
                     }
 
                 }
+                varNodeScopes.put(variable, varNode);
                 modelBuilder.setCurrentObject(variable);
                 Collection<TypeUsage> types = 
ModelUtils.resolveSemiTypeOfExpression(modelBuilder, init);
                 if (modelBuilder.getCurrentWith() != null) {
@@ -2636,6 +2643,7 @@ public class ModelVisitor extends PathNodeVisitor 
implements ModelResolver {
                 }
                 if (variable != null) {
                     variable.setJsKind(JsElement.Kind.OBJECT_LITERAL);
+                    varNodeScopes.put(variable, varNode);
                     modelBuilder.setCurrentObject(variable);
                 }
             }
@@ -2747,6 +2755,9 @@ public class ModelVisitor extends PathNodeVisitor 
implements ModelResolver {
 
 
             }
+        }
+        if (varNodeScopes.containsKey(modelBuilder.getCurrentObject())) {
+            varNodeScopes.remove(modelBuilder.getCurrentObject());
             modelBuilder.reset();
         }
         return super.leaveVarNode(varNode);
diff --git 
a/webcommon/javascript2.model/test/unit/data/testfiles/model/classInAnonymousFunction.js
 
b/webcommon/javascript2.model/test/unit/data/testfiles/model/classInAnonymousFunction.js
new file mode 100644
index 0000000000..2d05a5fb09
--- /dev/null
+++ 
b/webcommon/javascript2.model/test/unit/data/testfiles/model/classInAnonymousFunction.js
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+(function () {
+
+    class Directory {
+        constructor(displayName) {
+            this.displayName = displayName;
+        }
+    }
+
+    class ImageFile{
+        constructor(displayName){
+            this.displayName = displayName;
+        }
+    }
+})();
diff --git 
a/webcommon/javascript2.model/test/unit/data/testfiles/model/classInAnonymousFunction.js.model
 
b/webcommon/javascript2.model/test/unit/data/testfiles/model/classInAnonymousFunction.js.model
new file mode 100644
index 0000000000..03610cc59f
--- /dev/null
+++ 
b/webcommon/javascript2.model/test/unit/data/testfiles/model/classInAnonymousFunction.js.model
@@ -0,0 +1,29 @@
+FUNCTION classInAnonymousFunction [ANONYMOUS: false, DECLARED: true - 
classInAnonymousFunction, MODIFIERS: PUBLIC, FILE]
+# RETURN TYPES
+undefined, RESOLVED: true
+# PROPERTIES
+classInAnonymousFunctionL#20 : FUNCTION classInAnonymousFunctionL#20 
[ANONYMOUS: true, DECLARED: true - classInAnonymousFunctionL#20, MODIFIERS: 
PUBLIC, FUNCTION]
+                             # RETURN TYPES
+                             undefined, RESOLVED: true
+                             # PROPERTIES
+                             Directory : OBJECT Directory [ANONYMOUS: false, 
DECLARED: true - Directory, MODIFIERS: PUBLIC, CLASS]
+                                       # PROPERTIES
+                                       constructor : FUNCTION constructor 
[ANONYMOUS: false, DECLARED: true - constructor, MODIFIERS: PUBLIC, CONSTRUCTOR]
+                                                   # RETURN TYPES
+                                                   
classInAnonymousFunctionL#20.Directory, RESOLVED: true
+                                                   # PARAMETERS
+                                                   OBJECT displayName 
[ANONYMOUS: false, DECLARED: true - displayName, MODIFIERS: PUBLIC, PARAMETER]
+                                                   # PROPERTIES
+                                                   arguments : OBJECT 
arguments [ANONYMOUS: false, DECLARED: false - arguments, MODIFIERS: PRIVATE, 
VARIABLE]
+                                       displayName : OBJECT displayName 
[ANONYMOUS: false, DECLARED: true - displayName, MODIFIERS: PUBLIC, PROPERTY]
+                             ImageFile : OBJECT ImageFile [ANONYMOUS: false, 
DECLARED: true - ImageFile, MODIFIERS: PUBLIC, CLASS]
+                                       # PROPERTIES
+                                       constructor : FUNCTION constructor 
[ANONYMOUS: false, DECLARED: true - constructor, MODIFIERS: PUBLIC, CONSTRUCTOR]
+                                                   # RETURN TYPES
+                                                   
classInAnonymousFunctionL#20.ImageFile, RESOLVED: true
+                                                   # PARAMETERS
+                                                   OBJECT displayName 
[ANONYMOUS: false, DECLARED: true - displayName, MODIFIERS: PUBLIC, PARAMETER]
+                                                   # PROPERTIES
+                                                   arguments : OBJECT 
arguments [ANONYMOUS: false, DECLARED: false - arguments, MODIFIERS: PRIVATE, 
VARIABLE]
+                                       displayName : OBJECT displayName 
[ANONYMOUS: false, DECLARED: true - displayName, MODIFIERS: PUBLIC, PROPERTY]
+                             arguments : OBJECT arguments [ANONYMOUS: false, 
DECLARED: false - arguments, MODIFIERS: PRIVATE, VARIABLE]
diff --git 
a/webcommon/javascript2.model/test/unit/data/testfiles/model/classInAnonymousFunction2.js
 
b/webcommon/javascript2.model/test/unit/data/testfiles/model/classInAnonymousFunction2.js
new file mode 100644
index 0000000000..64c9739527
--- /dev/null
+++ 
b/webcommon/javascript2.model/test/unit/data/testfiles/model/classInAnonymousFunction2.js
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+(function () {
+    class Directory {
+        constructor(displayName) {
+            this.displayName = displayName;
+        }
+    }
+
+    class ImageFile{
+        constructor(displayName){
+            this.displayName = displayName;
+        }
+    }
+
+    function getJsonData(folderURL) {
+        const body = folderURL;
+    }
+})();
\ No newline at end of file
diff --git 
a/webcommon/javascript2.model/test/unit/data/testfiles/model/classInAnonymousFunction2.js.model
 
b/webcommon/javascript2.model/test/unit/data/testfiles/model/classInAnonymousFunction2.js.model
new file mode 100644
index 0000000000..487e4d50d2
--- /dev/null
+++ 
b/webcommon/javascript2.model/test/unit/data/testfiles/model/classInAnonymousFunction2.js.model
@@ -0,0 +1,37 @@
+FUNCTION classInAnonymousFunction2 [ANONYMOUS: false, DECLARED: true - 
classInAnonymousFunction2, MODIFIERS: PUBLIC, FILE]
+# RETURN TYPES
+undefined, RESOLVED: true
+# PROPERTIES
+classInAnonymousFunction2L#20 : FUNCTION classInAnonymousFunction2L#20 
[ANONYMOUS: true, DECLARED: true - classInAnonymousFunction2L#20, MODIFIERS: 
PUBLIC, FUNCTION]
+                              # RETURN TYPES
+                              undefined, RESOLVED: true
+                              # PROPERTIES
+                              Directory   : OBJECT Directory [ANONYMOUS: 
false, DECLARED: true - Directory, MODIFIERS: PUBLIC, CLASS]
+                                          # PROPERTIES
+                                          constructor : FUNCTION constructor 
[ANONYMOUS: false, DECLARED: true - constructor, MODIFIERS: PUBLIC, CONSTRUCTOR]
+                                                      # RETURN TYPES
+                                                      
classInAnonymousFunction2L#20.Directory, RESOLVED: true
+                                                      # PARAMETERS
+                                                      OBJECT displayName 
[ANONYMOUS: false, DECLARED: true - displayName, MODIFIERS: PUBLIC, PARAMETER]
+                                                      # PROPERTIES
+                                                      arguments : OBJECT 
arguments [ANONYMOUS: false, DECLARED: false - arguments, MODIFIERS: PRIVATE, 
VARIABLE]
+                                          displayName : OBJECT displayName 
[ANONYMOUS: false, DECLARED: true - displayName, MODIFIERS: PUBLIC, PROPERTY]
+                              ImageFile   : OBJECT ImageFile [ANONYMOUS: 
false, DECLARED: true - ImageFile, MODIFIERS: PUBLIC, CLASS]
+                                          # PROPERTIES
+                                          constructor : FUNCTION constructor 
[ANONYMOUS: false, DECLARED: true - constructor, MODIFIERS: PUBLIC, CONSTRUCTOR]
+                                                      # RETURN TYPES
+                                                      
classInAnonymousFunction2L#20.ImageFile, RESOLVED: true
+                                                      # PARAMETERS
+                                                      OBJECT displayName 
[ANONYMOUS: false, DECLARED: true - displayName, MODIFIERS: PUBLIC, PARAMETER]
+                                                      # PROPERTIES
+                                                      arguments : OBJECT 
arguments [ANONYMOUS: false, DECLARED: false - arguments, MODIFIERS: PRIVATE, 
VARIABLE]
+                                          displayName : OBJECT displayName 
[ANONYMOUS: false, DECLARED: true - displayName, MODIFIERS: PUBLIC, PROPERTY]
+                              arguments   : OBJECT arguments [ANONYMOUS: 
false, DECLARED: false - arguments, MODIFIERS: PRIVATE, VARIABLE]
+                              getJsonData : FUNCTION getJsonData [ANONYMOUS: 
false, DECLARED: true - getJsonData, MODIFIERS: PRIVATE, METHOD]
+                                          # RETURN TYPES
+                                          undefined, RESOLVED: true
+                                          # PARAMETERS
+                                          OBJECT folderURL [ANONYMOUS: false, 
DECLARED: true - folderURL, MODIFIERS: PUBLIC, PARAMETER]
+                                          # PROPERTIES
+                                          arguments : OBJECT arguments 
[ANONYMOUS: false, DECLARED: false - arguments, MODIFIERS: PRIVATE, VARIABLE]
+                                          body      : OBJECT body [ANONYMOUS: 
false, DECLARED: true - body, MODIFIERS: PRIVATE, CONSTANT]
diff --git 
a/webcommon/javascript2.model/test/unit/src/org/netbeans/modules/javascript2/model/ModelTest.java
 
b/webcommon/javascript2.model/test/unit/src/org/netbeans/modules/javascript2/model/ModelTest.java
index e7d630599b..8042180285 100644
--- 
a/webcommon/javascript2.model/test/unit/src/org/netbeans/modules/javascript2/model/ModelTest.java
+++ 
b/webcommon/javascript2.model/test/unit/src/org/netbeans/modules/javascript2/model/ModelTest.java
@@ -298,4 +298,12 @@ public class ModelTest extends ModelTestBase {
     public void testClassConstructor() throws Exception {
         checkModel("testfiles/model/classConstructor.js");
     }
+
+    public void testClassInAnonymousFunction() throws Exception {
+        checkModel("testfiles/model/classInAnonymousFunction.js");
+    }
+
+    public void testClassInAnonymousFunction2() throws Exception {
+        checkModel("testfiles/model/classInAnonymousFunction2.js");
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

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

Reply via email to