Bug 256463 - [compiler] Support common debug pattern in unreachable code detection
Summary: [compiler] Support common debug pattern in unreachable code detection
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.5   Edit
Hardware: PC Windows XP
: P3 enhancement (vote)
Target Milestone: 3.5 M4   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 313514 (view as bug list)
Depends on:
Blocks: 256796
  Show dependency tree
 
Reported: 2008-11-25 11:59 EST by Markus Keller CLA
Modified: 2016-01-14 14:17 EST (History)
5 users (show)

See Also:


Attachments
Proposed patch (43.76 KB, patch)
2008-11-26 12:42 EST, Philipe Mulet CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Keller CLA 2008-11-25 11:59:23 EST
I20081119-1600

Follow-up to bug 48399.

After enabling the new dead code detection compiler option, we found that most hits in our codebase were debug switches as exemplified in JLS3 13.4.9 and 14.21:

class Flags { final static boolean DEBUG = true; }
class Test {
    public static void main(String[] args) {
        if (Flags.DEBUG)
            System.out.println("debug is true");
    }
}

Could you add this as a sub-option of COMPILER_PB_DEAD_CODE? I would only expect this exception rule to suppress warnings of one of the forms ...

- 'if (DEBUG) THEN' or
- 'if (DEBUG) THEN else ELSE'

... where ...

- DEBUG is the qualified or unqualified name of a 'static final boolean' field which is initialized to either 'true' or 'false', and
- either THEN or ELSE is a statement that is marked as dead code.
Comment 1 Philipe Mulet CLA 2008-11-25 12:52:52 EST
What about ?

if (DEBUG_LEVEL == 1) {
  ...
}

Comment 2 Markus Keller CLA 2008-11-25 13:37:24 EST
> if (DEBUG_LEVEL == 1) {
>   ...
> }

My guess is that this would lower the rate of remaining false positives after comment 0 from 1% to 0.9%. But the drawback would be that there's no easy rule to describe this condition.

E.g. the rule "suppress the problem if the condition contains a reference to a static final field which is initialized by a literal" would also suppress

       if (MyEvent.CHANGED == MyEvent.NEW) { ... }
or     if (0 == MyEvent.NEW) { ... }

, although this was actually meant to be 'if (event.type == MyEvent.NEW)'.
Comment 3 Dani Megert CLA 2008-11-26 05:12:12 EST
>What about ?
>
>if (DEBUG_LEVEL == 1) {
>  ...
>}
I know that there are more patterns beside the one from comment 0. The question is which ones are common. I did a scan in the SDK and found that lots of plug-ins use the pattern from comment 0 while I found almost no DEBUG_LEVEL case. Note that I'm not against also supporting additional patterns, but I don't buy the argument that only because there's yet another case we can't satisfy the 90% (or higher) case.

Just FYI: when I enabled the problem in my workspace I got 330 dead code problems reported, out of which I found only 17 real issues and probably missed some due to the big amount of false positives.
Comment 4 Philipe Mulet CLA 2008-11-26 05:36:39 EST
Don't get me wrong. I am willing to add support for a good heuristic. I am only trying to come up with a reasonable good one where we cannot be blamed to be to nice to ourselves.

What about these cases:

(1)
if (!TRACE_DISABLED)
   System.out.println("fake reachable1");

---> I think we should tolerate, as another known pattern.

(2)
if (DEBUG && b)
   System.out.println("fake reachable2");

--> presently, it complains both against 'b' and thenStatement
--> I would keep that, since not a simple pattern.
--> argue that one could write instead: 
             if (DEBUG) {
                if (b) {
                   ...
                }
             }


(3)
if (DEBUG && check())
   System.out.println("fake reachable3");

--> presently, it complains both against 'check()' and thenStatement
--> I would keep that, since not a simple pattern.
--> argue that one could write instead: 
             if (DEBUG) {
                if (check()) {
                   ...
                }
             }

(4)
if (b && DEBUG)
   System.out.println("fake reachable4");

---> would complain, I don't think anyone write such code 
     (i.e. DEBUG check goes first)

(5)
if (check() && DEBUG)
   System.out.println("fake reachable5");

---> would complain, I don't think anyone write such code 
     (i.e. DEBUG check goes first)

(6)
if (DEBUG_LEVEL > 1) 
   System.out.println("fake reachable6"); //$NON-NLS-1$

---> I think we should tolerate, as another known pattern.

Comment 5 Dani Megert CLA 2008-11-26 05:47:32 EST
Agree with comment 4. I would add two sub-options:
[ ] Ignore if-test on boolean constant  (e.g. if (DEBUG) ...)
[ ] Ignore if-test on number constant (e.g. if (DEBUG_LEVEL > 1)

Case 6) could also handle floats and double I guess.
Comment 6 Philipe Mulet CLA 2008-11-26 06:05:33 EST
Does it really need 2 sub prefs ?

[ ] Ignore trivial if check on constant  (e.g. if (DEBUG), if (DEBUG_LEVEL > 1)


(and yes, the binary expression could tolerate any sort of constants in there, like if (DEBUG == true) ...

Comment 7 Dani Megert CLA 2008-11-26 06:11:17 EST
>Does it really need 2 sub prefs ?
Yes, because for people (90% case) don't use the second pattern and if they have code like: SOME_CONST > 1 they would like this to be flagged.
Comment 8 Philipe Mulet CLA 2008-11-26 06:49:34 EST
The consensus here (Jerome, David, Frederic and I) is to go for one sub pref for trivial checks.
Comment 9 Dani Megert CLA 2008-11-26 06:53:08 EST
Too bad JDT UI are only two people so we have no chance when it comes to voting :-(

The UI would be much clearer as we could explain the two cases - and as said, 90% don't use the second pattern. Just do a scan of the SDK once.
Comment 10 Markus Keller CLA 2008-11-26 07:14:46 EST
> The consensus here (Jerome, David, Frederic and I) is to go for one sub pref
> for trivial checks.

+1 for only one sub-pref, but only for trivial *boolean* checks.
Comment 11 Dani Megert CLA 2008-11-26 07:17:56 EST
>+1 for only one sub-pref, but only for trivial *boolean* checks.
That would also be my vote unless we find that the other case is really common and a pain for users.
Comment 12 Philipe Mulet CLA 2008-11-26 07:40:13 EST
Triviality can be argued further, I agree. I can turn off the "if (DEBUG_LEVEL > 0)" scenario to see if this becomes a popular request to add.
Comment 13 Markus Keller CLA 2008-11-26 08:25:57 EST
I would even enable dead code detection by default, but only with
'Ignore if-test on boolean constant' enabled as well.

Even if we had the more elaborate option for number checks, I would not enable
that one by default (since it could wrongly hide real issues, which I think is not the case with only the boolean checks enabled).
Comment 14 Dani Megert CLA 2008-11-26 09:17:31 EST
Just for the records: I loaded all SDK source into a fresh workspace and did the following two case sensitive regex searches:
1) if.*\(\s*DEBUG.*\) ==> 1315 matches (including the ones below)
2) if.*\(\s*DEBUG.*[<>].*\) ==> 2 matches (1 in o.e.jdt.core and 1 in o.e.osgi)
Comment 15 Philipe Mulet CLA 2008-11-26 12:42:18 EST
Created attachment 118822 [details]
Proposed patch

Only tolerates: if(<ref to constant>) and if(!<ref to constant>)
Comment 16 Philipe Mulet CLA 2008-11-26 13:06:18 EST
Released for 3.5M4.
Fixed


If triviality needs to be argued further, please enter a separate bug report.
Comment 17 Dani Megert CLA 2008-11-27 04:18:04 EST
Perfect! Thanks for the quick fix.

When enabled on my plug-ins, it found exactly those locations where a potential problem is.

BTW: I would follow Markus's suggestion and set this to warning by default.
Comment 18 Jerome Lanneluc CLA 2008-12-09 05:58:15 EST
Verified for 3.5M4 using I20081209-0100
Comment 19 Stephan Herrmann CLA 2016-01-14 14:17:29 EST
*** Bug 313514 has been marked as a duplicate of this bug. ***