Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 376550

Summary: "Method can be static" warning on method that accesses instance field in inner class
Product: [Eclipse Project] JDT Reporter: Nick Radov <nradov>
Component: CoreAssignee: Ayushman Jain <amj87.iitr>
Status: VERIFIED FIXED QA Contact:
Severity: minor    
Priority: P3 CC: amj87.iitr, deepakazad, satyam.kandula, srikanth_sankaran, stephan.herrmann
Version: 3.8Flags: srikanth_sankaran: review+
stephan.herrmann: review+
Target Milestone: 3.8 RC1   
Hardware: PC   
OS: Windows 7   
Whiteboard:
Attachments:
Description Flags
proposed fix v1.0 + regression tests
none
proposed fix v1.1 + regression tests none

Description Nick Radov CLA 2012-04-11 20:36:39 EDT
Build Identifier: 20120216-1857

The "Method can be static" code style warning does not properly account for anonymous inner classes declared within methods.

Reproducible: Always

Steps to Reproduce:
1. From the menu select Window, Preferences.
2. Go to Java, Compiler, Errors/Warnings.
3. In the Code Style section set "Method can be static" to "Warning".
4. Compile the following code.

import java.util.ArrayList;
import java.util.Collection;

public class CanBeStatic {

    private Object o = new Object();

    public final Collection<Object> go() {
        return new ArrayList<Object>() {
            {
                add(o);
            }
        };
    }

}

Notice that you get the "can be declared as static" on the go() method. But the warning is incorrect: if you declare the method as static then it won't compile because it references an instance field.
Comment 1 Ayushman Jain CLA 2012-04-12 02:33:44 EDT
Thanks for the test case. I will take a look.
Comment 2 Ayushman Jain CLA 2012-05-08 02:50:49 EDT
Created attachment 215226 [details]
proposed fix v1.0 + regression tests

For the current bug, the problem was in BlockScope.resetEnclosingMethodStaticFlag() i.e. we expected a method declaration to be associated with a method scope but in this case there is a type declaration instead, since this is an intiliazation scope. So the resetting of the CanBeStatic flag did not happen for go().

However, digging deeper I found that the current way of resetting the flag of all enclosing methods is over-eager and even if a local class method cannot be static, there can be cases where the enclosing method can be static. To really reset the CanBeStatic only upto the enclosingMethod which actually cannot be static, I added BlockScope.resetDeclaringClassMethodStaticFlag(TypeBinding). Take for example, the case below:

class X{
  int i1= 1;
  void foo() {
      class Local {
          int i2 = 1;
          void localMethod() {
              i2 = 1;
          }
      }
   }
}

The localMethod cannot be static because of an unqualified access to an instance field of its declaring class, however foo() can be still be static. Hence just finding an unqalified field reference is not a necessary condition for all enclosing methods to not be static. We need to find where the field is actually declared and limit the resetting upto that scope.
Comment 3 Ayushman Jain CLA 2012-05-08 02:56:55 EDT
Srikanth, can you review for RC1? This fix should make this diagnostic more usable.
Comment 4 Srikanth Sankaran CLA 2012-05-09 02:03:35 EDT
(In reply to comment #3)
> Srikanth, can you review for RC1? This fix should make this diagnostic more
> usable.

Sure thing. Marking Stephan as an additional reviewer. Stephan, Thanks in
advance.
Comment 5 Srikanth Sankaran CLA 2012-05-10 07:18:48 EDT
Patch looks alright to me - One thing that looked strange is though
is the difference between the code blocks in FieldReference and MessageSend.
What justifies this change ?
Comment 6 Ayushman Jain CLA 2012-05-10 08:04:17 EDT
Created attachment 215387 [details]
proposed fix v1.1 + regression tests

(In reply to comment #5)
> Patch looks alright to me - One thing that looked strange is though
> is the difference between the code blocks in FieldReference and MessageSend.
> What justifies this change ?

They should both be the same. Only the enclosing method's flag should be reset, since using a 'this' reference, we cannot call an outer class method anyway. I corrected it in the new patch.
Comment 7 Ayushman Jain CLA 2012-05-14 04:07:13 EDT
Released in master via commit 5903b5532387cc7ed73791cbff2d52e4ceee6d52.

Stephan, you can probably take this up for verification and do the review alongside. Thanks!
Comment 8 Satyam Kandula CLA 2012-05-17 02:45:10 EDT
Found a minor problem with this fix. Filed bug 379784 to take care of this.
Verified for 4.2RC1 using build I20120516-1900.
Comment 9 Stephan Herrmann CLA 2012-05-17 12:27:44 EDT
How about this case:

public class X<T> {
	public void foo() {
		java.util.List<T> k;
	}
}

It reports "The method foo() from the type X<T> can potentially be declared as static" but adding "static" yields of course:
"Cannot make a static reference to the non-static type T".

Is that the meaning of "can potentially" (i.e., a known limitation of the analysis), or should I file a new bug for that?

I checked that it has been this way before (3.7 and all 3.8 milestones).

BTW: I've added other cases where the analysis is shyer than necessary to bug 379784.
Comment 10 Ayushman Jain CLA 2012-05-17 12:34:39 EDT
(In reply to comment #9)
> How about this case:
> 
> public class X<T> {
>     public void foo() {
>         java.util.List<T> k;
>     }
> }
> 
> It reports "The method foo() from the type X<T> can potentially be declared as
> static" but adding "static" yields of course:
> "Cannot make a static reference to the non-static type T".
> 
> Is that the meaning of "can potentially" (i.e., a known limitation of the
> analysis), or should I file a new bug for that?

The only difference between "can potentially" and "can" is that the latter gets reported for methods that won't be overriden. So try private/final methods to toggle between the two. Please add your testcase and anything else you find related to type parameters to bug 378674.
Comment 11 Stephan Herrmann CLA 2012-05-17 13:18:45 EDT
Another fup (not a regression) is in Bug 379834.
Comment 12 Stephan Herrmann CLA 2012-05-17 13:51:23 EDT
+1 from me, considering that all the issues I found already existed before this patch.