=== modified file 'rules/annotations/oo_references.rules'
--- old/rules/annotations/oo_references.rules	2021-04-28 15:44:53 +0000
+++ new/rules/annotations/oo_references.rules	2021-07-01 21:41:38 +0000
@@ -7,7 +7,7 @@
 **
 ** Copyright (c) 2018-2021, Golden Code Development Corporation.
 **
-** _#_ _I_ __Date__ _______________________________Description_________________________________
+** _#_ _I_ __Date__ ______________________________________Description________________________________________
 ** 001 GES 20181206 First version.
 **      OM 20181217 Wrapped the literals passed as parameters to OO methods.
 ** 002 GES 20190119 Fixed direct property access within getters and setters.
@@ -37,6 +37,8 @@
 **                  INPUT modifier exists or not.
 **     CA  20210428 When a property is part of a lvalue for an assign-style stmt, save the setter javaname so
 **                  later on, when that is injected, the proper javaname is used.
+**     GES 20210701 Fix class name references which are to static members of a parent class. This is a 4GL
+**                  quirk.
 */
  -->
  
@@ -115,6 +117,9 @@
    <variable name="ename"     type="java.lang.String" />
    <variable name="pmodes"    type="java.lang.String" />
    <variable name="pmode"     type="java.lang.String" />
+   <variable name="clsname"   type="java.lang.String" />
+   <variable name="foundIn"   type="java.lang.String" />
+   <variable name="javacls"   type="java.lang.String" />
    <variable name="propref"   type="com.goldencode.ast.Aast" />
    <variable name="ref"       type="com.goldencode.ast.Aast" />
    <variable name="ref2"      type="com.goldencode.ast.Aast" />
@@ -126,6 +131,7 @@
    <variable name="subref"    type="com.goldencode.ast.Aast" />
    <variable name="idxref"    type="com.goldencode.ast.Aast" />
    <variable name="eref"      type="com.goldencode.ast.Aast" />
+   <variable name="member"    type="com.goldencode.ast.Aast" />
    <variable name="idxpos"    type="java.lang.Integer" />
    <variable name="paramIdx"  type="java.lang.Integer" />
    <variable name="getter"    type="com.goldencode.ast.Aast" />
@@ -241,6 +247,28 @@
          <action>usingClasses.addAll(getAllClassesInPackage(usingPkg))</action>
          
       </rule>
+      
+      <!-- the 4GL has a quirk where a qualified static reference to a parent class member can be made
+           using a child class name as the referent; see #4978; rewrite the CLASS_NAME details to point to 
+           the actual class; this MUST be above the next section where CLASS_NAME references will be
+           annotated in more detail -->
+      <rule>evalLib("isStaticClassReference", this)
+         <action>member = copy.nextSibling</action>
+         
+         <!-- at this time we limit this to method calls; it may need to be opened up if this is also
+              possible for data members -->
+         <rule>member.type &gt; prog.begin_oo_meth and member.type &lt; prog.end_oo_meth
+            <action>clsname = copy.getAnnotation("qualified")</action>
+            <action>foundIn = member.getAnnotation("found-in-cls")</action>
+            <rule>clsname != null and foundIn != null and !foundIn.toLowerCase().equals(clsname)
+               <!-- rewrite the CLASS_NAME annotations to be the correct class -->
+               <action>putNote("qualified", foundIn.toLowerCase())</action>
+               <action>
+                  putNote("source-file", #(java.lang.String) member.getAnnotation("found-in-source-file"))
+               </action>
+            </rule>
+         </rule>
+      </rule>      
    
       <rule>(evalLib("isObjectType", this) or this.type == prog.kw_funct) and
             isNote("qualified") and isNote("source-file")

=== modified file 'rules/convert/oo_calls.rules'
--- old/rules/convert/oo_calls.rules	2021-02-16 18:01:41 +0000
+++ new/rules/convert/oo_calls.rules	2021-07-01 22:35:18 +0000
@@ -7,7 +7,7 @@
 **
 ** Copyright (c) 2018-2021, Golden Code Development Corporation.
 **
-** _#_ _I_ __Date__ _______________________________Description_________________________________
+** _#_ _I_ __Date__ ______________________________________Description________________________________________
 ** 001 CA  20181214 First version.
 ** 002 CA  20190219 NEW statement requires parameter modes as set at the referenced constructor.
 **                  Changed class event subscribe/unsubscribe to emit first argument as an legacy
@@ -29,6 +29,7 @@
 **                  for OO properties/variables (static and non-static).
 **     CA  20210216 Fix for the 'cast-to-object' case for a single extent argument in a dynamic call, when
 **                  INPUT modifier exists or not.
+**     GES 20210701 Moved code into a common function isStaticClassReference().
 */
  -->
  
@@ -149,14 +150,8 @@
          </rule>
       </rule>
       
-      <rule>this.type == prog.class_name                           and 
-            parent.type == prog.object_invocation                  and
-            this.indexPos == 0
-            <!-- 
-               following is required to not emit in case of a SUBSCRIBE(oo.Bar:staticMethod) 
-            -->
-            and not(parent.parent.type == prog.object_invocation and 
-                    parent.parent.firstChild.type == prog.class_event)
+      <!-- emit class names as referents for a static member -->
+      <rule>evalLib("isStaticClassReference", this)
          <action>
             createJavaAst(java.reference, 
                           #(java.lang.String) execLib("resolveClassReference", copy, null), 

=== modified file 'rules/include/common-progress.rules'
--- old/rules/include/common-progress.rules	2021-05-04 14:06:39 +0000
+++ new/rules/include/common-progress.rules	2021-07-01 22:34:25 +0000
@@ -450,6 +450,7 @@
 **                           in favor of runtime evaluation.
 **     OM  20210410          Added KW_COL_CP to temp-table field's set of attributes.
 **     ME  20210504          Added override names for logging and web OO builtins.
+**     GES 20210701          Added isStaticClassReference().
 */
  -->
  
@@ -3113,6 +3114,20 @@
          evalLib('bin_operators', optype)
       </function>
       
+      <function name="isStaticClassReference">
+         <parameter name="target"  type="com.goldencode.ast.Aast" />
+         <return    name="clsref"  type="java.lang.Boolean" />
+         
+         <!-- the class_event check is required to not emit in case of a SUBSCRIBE(oo.Bar:staticMethod) -->
+         <rule>
+            clsref = (target.type == prog.class_name                      and 
+                      target.parent.type == prog.object_invocation        and
+                      target.indexPos == 0                                and
+                      not(target.parent.parent.type == prog.object_invocation   and 
+                          target.parent.parent.firstChild.type == prog.class_event))
+         </rule>
+      </function>
+      
       <function name="resolveClassReference">
          <parameter name="target"  type="com.goldencode.ast.Aast" />
          <parameter name="fmt"     type="java.lang.String" />

=== modified file 'src/com/goldencode/p2j/uast/ClassDefinition.java'
--- old/src/com/goldencode/p2j/uast/ClassDefinition.java	2021-06-16 13:09:43 +0000
+++ new/src/com/goldencode/p2j/uast/ClassDefinition.java	2021-07-02 18:43:04 +0000
@@ -103,6 +103,8 @@
 **     CA  20210609          Reworked INPUT/INPUT-OUTPUT parameters to a new approach, where they are explicitly 
 **                           initialized at the method's execution, and not at the caller's arguments.
 **     CA  20210616          Fixed incremental conversion for enums - do not mark them as static.
+**     GES 20210702          Allow parent hierarchy lookup for static methods.  This is a 4GL quirk that is not
+**                           present in Java. See #4978.  Removed dead code and some debugging code.
 */
 
 /*
@@ -2206,29 +2212,6 @@
    }
 
    /**
-    * Reports if the given method is a static member of the given class.
-    *
-    * @param    name
-    *           Member name to lookup.
-    * @param    access
-    *           Access mode (<code>KW_PUBLIC</code>, <code>KW_PROTECTD</code>
-    *           or <code>KW_PRIVATE</code>).
-    * @param    internal
-    *           <code>true</code> if the lookup is internal to the current class definition.
-    *
-    * @return   <code>true</code> if the member is static.  <code>false</code> otherwise
-    *           including the case where the member does not exist at all.
-    */
-   public boolean isStaticMethod(String name, int access, boolean internal)
-   {
-      MemberData dat = guessMethod(name, access, true, internal);
-      
-      // TODO: this is not authoritative and could give a false even though there is a static
-      //       method of the same name
-      return (dat == null) ? false : dat.isStatic;
-   }
-   
-   /**
     * Get all defined methods in this class.
     * 
     * @return   All defined method names.
@@ -3007,9 +2990,8 @@
             }
          }
          
-         // there was no match in the current class, look up the parent hierarchy; static lookups
-         // only work for internal usage, non-static lookups always work
-         if (parents != null && (!isStatic || internal))
+         // there was no match in the current class, look up the parent hierarchy
+         if (parents != null)
          {
             // change access mode since we aren't allowed to see private stuff in parent
             int _access = (access == KW_PRIVATE) ? KW_PROTECTD : access;
@@ -3143,7 +3125,7 @@
          
          // only look up the parent hierarchy if we haven't got a match yet; static lookups only
          // work for internal usage, non-static lookups always work
-         if (mdat == null && parents != null && (!isStatic || internal))
+         if (mdat == null && parents != null)
          {
             // change access mode since we aren't allowed to see private stuff in parent
             int _access = (access == KW_PRIVATE) ? KW_PROTECTD : access;
@@ -3257,15 +3239,6 @@
       
       boolean first = isSetParam(name);
       
-      if ("Progress.Json.ObjectModel.JsonObject".equalsIgnoreCase(this.name) &&
-          "write".equalsIgnoreCase(name) &&
-          caller.length == 2 &&
-          caller[0].type.equals("longchar") &&
-          caller[1].type.equals("logical"))
-      {
-         int bogus = 14;
-      }
-      
       List<MemberData> list = candidates(name, caller.length, access, isStatic, internal, first, null);
             
       // quick out if there are no possible matches
@@ -3689,8 +3662,8 @@
          }
          
          // fuzzy matches are processed up the the parent hierarchy even if there are possible matches in
-         // the current class; static lookups only work for internal usage, non-static lookups always work
-         if (parents != null && (!isStatic || internal))
+         // the current class
+         if (parents != null)
          {
             // change access mode since we aren't allowed to see private stuff in parent
             int _access = (access == KW_PRIVATE) ? KW_PROTECTD : access;

