Bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used
Summary: [compiler] Warn for potential programming problem if an object is created but...
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.4   Edit
Hardware: PC Windows XP
: P3 enhancement with 1 vote (vote)
Target Milestone: 3.6 M5   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 285000
  Show dependency tree
 
Reported: 2008-06-10 04:36 EDT by Benno Baumgartner CLA
Modified: 2010-01-25 05:25 EST (History)
8 users (show)

See Also:
Olivier_Thomann: review+


Attachments
proposed implementation and tests (9.19 KB, patch)
2008-08-23 06:02 EDT, Stephan Herrmann CLA
no flags Details | Diff
proposed tests (4.77 KB, patch)
2008-08-31 11:44 EDT, Stephan Herrmann CLA
no flags Details | Diff
updated patch (20.08 KB, patch)
2009-12-05 14:44 EST, Stephan Herrmann CLA
no flags Details | Diff
patch v3 (26.58 KB, patch)
2010-01-12 16:07 EST, Stephan Herrmann CLA
Olivier_Thomann: iplog+
Olivier_Thomann: review+
Details | Diff
Updated patch (30.35 KB, patch)
2010-01-13 10:14 EST, Olivier Thomann CLA
no flags Details | Diff
Proposed fix for unused anonymous types (1.43 KB, patch)
2010-01-13 10:29 EST, Olivier Thomann CLA
no flags Details | Diff
Same patch with a regression test (3.43 KB, patch)
2010-01-13 10:31 EST, Olivier Thomann CLA
no flags Details | Diff
Category change (2.89 KB, patch)
2010-01-13 14:14 EST, Olivier Thomann CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Benno Baumgartner CLA 2008-06-10 04:36:01 EDT
I20080609-1311

Given:
public void foo() {
   if (bar())
       new IllegalArgumentException("You must not bar!");
}
Is:
 Compiler does not warn that this code is most probably a bug because the throw is missing
Should:
 Add a potential programming problem which flags this code and warns that the throw is missing

See bug 236332 for a real world use case.
Comment 1 Stephan Herrmann CLA 2008-08-23 06:02:15 EDT
Created attachment 110739 [details]
proposed implementation and tests

I suggest to check whether a throwable is instantiated but not used in any way.
IMHO, the following should not trigger a warning, although not directly throwing:
  new RuntimeException("How come?").printStackTrace();
  handleError(new Error("SNAFU"));
  whenDidThisHappen = new Exception("Now!");
  return new Exception("Do you still want to continue?");
Only if the allocation is actually used as a statement, it is very unlikely
(side-effect in a ctor??) that the code makes any sense.

The good news: Implementation of such "analysis" is really easy: 2 lines ;-)

See attached patch.

A few mundane things I wasn't quite sure about:
 * what codes to assign (IProblem, CompilerOptions)
 * where to add the tests

My patch makes it a configurable warning
 * suppressable by token "unused"
 * separate new compiler option - not yet integrated with Batch nor UI

A side note regarding irritants in CompilerOptions: those constants are 
approaching the ceiling of the 64 bits in a long. For a while I was
going to ask you devs to use these bits more sparingly, guess what:
in our variant we currently have 9 additional irritants. (58+9=67)
But rest assured, by now I found a way to handle 126 irritants :)
Comment 2 Stephan Herrmann CLA 2008-08-31 11:44:12 EDT
Created attachment 111358 [details]
proposed tests

I just noticed that the patch wizard ignores may additions in
org.eclipse.jdt.core.tests.compiler :(

So here's a patch containing the proposed tests, created on
the command line within project org.eclipse.jdt.core.tests.compiler.

Any comments?
Comment 3 Philipe Mulet CLA 2008-09-01 07:59:39 EDT
> But rest assured, by now I found a way to handle 126 irritants :)
Being curious. How did you do it ? I was thinking of holding onto an array of long, instead of just one. 
Comment 4 Stephan Herrmann CLA 2008-09-01 08:48:53 EDT
(In reply to comment #3)
> > But rest assured, by now I found a way to handle 126 irritants :)
> Being curious. 
:)

the irritant encoding is still a single long, bit 64 switches between
two sets. Remaining 63 bits are used as before. (2 x 63 = 126)
(so an irritant may have at most 2 bits set).

I now keep separate fields warningThreshold and errorThreshold for
each of these two sets.

Switching over an irritant is now cascaded in three steps:
1 check the switch bit
2 check for int vs. long range
3 switch over the individual constants

Computing the severity inspects the switch bit to select the
correct threshold value.

You can see the details here:
http://trac.objectteams.org/ot/changeset/18817

HTH
Comment 5 Philipe Mulet CLA 2008-09-01 10:36:21 EDT
This is similar to what I had in mind, reserve high bits for irritant to select group of irritants. The issue is that irritants cannot be composed any longer blindly.

Also I think you need to fix CompilationUnitDeclaration#suppressWarningIrritants
Comment 6 Stephan Herrmann CLA 2008-09-01 13:50:37 EDT
(In reply to comment #5)
> The issue is that irritants cannot be composed any longer blindly.

Yup, this applies to CompilerOptions#warningTokenToIrritants, which
can only group irritants from the same set.
I wouldn't see any other places that would want to compose irritants.
Do you see more?

> Also I think you need to fix
> CompilationUnitDeclaration#suppressWarningIrritants

Gee wiz, you caught me here. Yes, thanks, you're right.
Hm, that is a little trickier, and in this case I see your point 
of using arrays. I even tried both orderings of indices, but 
replacing the "long" leaves with "pairs of long" seems most "natural".

So this patch:
  http://trac.objectteams.org/ot/changeset/18958
is currently under test on our build machine.

Thanks for the hint.

BTW: have you had a chance to look at the patch in this bug?
(it's really simple)
Comment 7 Philipe Mulet CLA 2008-09-02 03:53:04 EDT
I will look at it. I am more skeptical about the general utility of such a warning.
Comment 8 Stephan Herrmann CLA 2008-09-02 07:32:01 EDT
(In reply to comment #7)
> I am more skeptical about the general utility of such a warning.

My equation was:
- only report in a very limited set of situations
  => extremely unlikely to raise false alarms
- implementation is trivial
+ IF it triggers the user will be very grateful

Comment 9 Philipe Mulet CLA 2008-09-03 04:25:06 EDT
See bug 245973 for issue with 64bit limitation with irritants. A patch is attached there with my current thinking.
Comment 10 Philipe Mulet CLA 2008-09-03 04:36:07 EDT
Re: patch
The situation where it will report a warning is extremely limited. 
Currently, only when codegen decides to optimize out the value. Note that this may arise in other situations than just statement expressions.

Codegen optimizations do make certain decisions:
e.g.
if (false && new Exception()) { 
}

Moreover, how is this more useful than flagging useless allocation in general ?
e.g.
   new Integer(0); // how useful is that ?

i.e. shouldn't the warning simply be reporting unused allocation ?


Comment 11 Philipe Mulet CLA 2008-09-03 04:40:39 EDT
BTW, checking allocated type for subtype of Throwable should rather be written as:

if (allocatedType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangThrowable, true) != null) {
}

as it will not force loading of Throwable in name environment. We want to minimize type loading for easing use of compiler when bootstrapping class library development (you do not need Throwable to be loaded).

Comment 12 Stephan Herrmann CLA 2008-09-03 08:02:57 EDT
(In reply to comment #10)
> The situation where it will report a warning is extremely limited. 

it is limited, yes.

> Currently, only when codegen decides to optimize out the value. Note that this
> may arise in other situations than just statement expressions.
> 
> Codegen optimizations do make certain decisions:
> e.g.
> if (false && new Exception()) { 
> }

You mean a user would expect the warning also for:
  e = false ? new Exception() : null;
But the primary bad smell here is the constant condition,
not the ignored value. 
In order to create a situation where the value would still
be ignored after replacing "false" with some useful value,
you would need to use the conditional expression as a statement,
but that's a syntax error to begin with.

> Moreover, how is this more useful than flagging useless allocation in general ?
> e.g.
>    new Integer(0); // how useful is that ?
> 
> i.e. shouldn't the warning simply be reporting unused allocation ?

Yes, might as well consider, 
but then
 - error message would be more general (can no longer suggest to add "throw")
 - this assumes that ctors are not used to create global side-effects, 
   an assumption which I considered fair for Throwables,
   but will perhaps not hold for all classes ever.
Comment 13 Philipe Mulet CLA 2008-09-03 09:16:55 EDT
> You mean a user would expect the warning also for:
>  e = false ? new Exception() : null;

Your implementation would raise a warning in this case, as codegen valueRequired is false there.
I was only writing a dumb example demonstrating that it may occur in various situations.


Re: flagging unused allocation in general over exception allocation. 
This at least would be more consistent with the limitation of the warning, I think.
Comment 14 Stephan Herrmann CLA 2008-09-03 10:17:15 EDT
(In reply to comment #13)
> > You mean a user would expect the warning also for:
> >  e = false ? new Exception() : null;
> 
> Your implementation would raise a warning in this case, as codegen
> valueRequired is false there.

No, generateCode is skipped for the then expression ;-)

> I was only writing a dumb example demonstrating that it may occur in various
> situations.

Currently I don't see any situations that would produce truely unexpected results.
I may have to look harder for a valid counter example.
Unfortunately I have to leave the discussion at this point - 
won't have internet the next days ... 
Comment 15 Benno Baumgartner CLA 2008-09-03 11:44:14 EDT
Here my 2 cents:
1. Issue a warning whenever an object is created without been used (assigned/thrown/member invoked)
2. Make this option configurable (of course) and off by default

At least in my code instantiating an object without using it is almost always certainly a bug because IMHO any side effect in a constructor, other then initializing the object, is bad programming style.
Comment 16 Remy Suen CLA 2008-11-07 04:54:22 EST
(In reply to comment #15)
> 1. Issue a warning whenever an object is created without been used
> (assigned/thrown/member invoked)

+1 for this since I just hit this problem and I remembered this enhancement request. I was trying to extend getAdapter(Class) but ended up doing nothing...

public Object getAdapter(Class adapter) {
  if (adapter.equals(X.class)) {
    new X(); // whoops! :(
  }
  return super.getAdapter(adapter);
}
Comment 17 Philipe Mulet CLA 2009-07-16 07:33:08 EDT
As said in comment 13, I would support the idea of yet another warning for diagnosing unnecessary object allocations, but I am pretty sure there are valid usecases out there some will tell us, which we will have to add special support for (given certain libs maybe); so this could be more time involving in the future.

Nice to have, but low prio to me.
Comment 18 Stephan Herrmann CLA 2009-07-17 05:23:52 EDT
(In reply to comment #17)

So, what does this mean? 3 people would like to see this warning
implemented, a patch plus tests exist.
The only jdt-core committer in this discussion states:

> Nice to have, but low prio to me.

Is there any workflow, how a feature that is low prio to the 
core committers can still be committed eventually?

If your judgement is: the given patch and tests are only the lesser
part of the effort, the larger part is still to come, please be more
specific, so I can make up my mind whether I feel it's worth
investing even more in this issue. And you know that I won't run
away after the patch is committed, i.e., I am willing to help also
in case people complain about this feature in the future.

(youre worries seem to be connected to recent discussions, e.g.,
regarding dead-code warnings, where people wish certain patterns
to be excluded from the analysis? Maybe considering all these
unnecessary-code warnings together will eventually produce an even
better way of fine-tuning such warnings??)

Also note, that I was careful NOT to say:
> instantiating an object without using it is almost always
> certainly a bug because IMHO any side effect in a constructor, other then
> initializing the object, is bad programming style.

I understand that a compiler must not be too harsh in deciding what
is or isn't bad programming style. Some people are likely to feel
offended by any such decision, so yes, I'm open to looking for
even better ways how we prevent style-related warnings from getting
in some people's ways.
But this issue also has the potential of exposing real bugs as several 
of us have observed in real life.
Comment 19 Dani Megert CLA 2009-07-17 05:43:14 EDT
-1 to only handle unused Throwable creation but +1 to to detected the creation of any unused object. And yes, it's bad coding style ;-)

Philippe, maybe we should adjust the summary?
Comment 20 Stephan Herrmann CLA 2009-07-17 11:38:37 EDT
(In reply to comment #19)
ups, there _is_ another jdt-core committer in this discussion ;-)

> -1 to only handle unused Throwable creation but +1 to to detected the creation
> of any unused object.

d'accord

> And yes, it's bad coding style ;-)

I don't disagree ;-)
only: experience tells, that it's easy to create border line
cases where "bad" would be too strong a word - but that's just
the general reason why warnings should be configurable.
I assume this one would rank as "unused"?

Comment 21 Dani Megert CLA 2009-07-29 07:18:20 EDT
>(In reply to comment #19)
>ups, there _is_ another jdt-core committer in this discussion ;-)
Almost (I'm not a JDT Core committer but overall JDT co-lead).
Comment 22 Olivier Thomann CLA 2009-07-29 09:00:52 EDT
This new warning should go under the "unused" umbrella. This means that if users are using 1.5 code they can use the @SuppressWarning annotation to get rid of the warning in some corner cases.
I opened bug 285000 for the UI side of this option.

I would rename the option in the patch for UnusedObjectAllocation instead of UnusedThrowableAllocation.
Comment 23 Olivier Thomann CLA 2009-07-29 09:01:54 EDT
Philippe, any comment?

I think this fits well inside the "unused" warnings.
Comment 24 Stephan Herrmann CLA 2009-07-29 11:02:00 EDT
(In reply to comment #22)
> This new warning should go under the "unused" umbrella. This means that if
> users are using 1.5 code they can use the @SuppressWarning annotation to get
> rid of the warning in some corner cases.

Right (it's is already included in patch & tests).

> I opened bug 285000 for the UI side of this option.
> 
> I would rename the option in the patch for UnusedObjectAllocation instead of
> UnusedThrowableAllocation.

sure.

Just let me know, if you'd like me to update the patch
and/or add more tests.
Comment 25 Olivier Thomann CLA 2009-07-29 15:01:53 EDT
Updating title.
Reassigning.

Philippe, let me know if this is fine for you.
Comment 26 Stephan Herrmann CLA 2009-12-05 14:44:07 EST
Created attachment 153869 [details]
updated patch

I guess we have sufficient authoritative +1 on this bug to proceed ;-)

So here is an updated patch that is also more complete wrt. tests.

The warning has been broadened beyond Throwable and the constants etc.
renamed accordingly.

I was wondering whether "allocating" would be the best term in the message
(vs. "instantiating" or "creating"), but it seems that "allocating" is 
indeed consistently used by compiler messages.
Comment 27 Dani Megert CLA 2009-12-10 05:51:16 EST
I didn't review the patch but quickly tried it out:
- the default severity needs to be 'Ignore' i.e. off by default
- the message should be closer to unused variables:
  ==> "The allocated object is never used"
Comment 28 Stephan Herrmann CLA 2009-12-10 07:57:25 EST
(In reply to comment #27)
> I didn't review the patch but quickly tried it out:
> - the default severity needs to be 'Ignore' i.e. off by default

This probably won't change your mind, but I do think that Eclipse
is hiding a few valuable features from users who'll never notice
that something has been added. My favorite example in this regard
is "Java Type Indicators". Many Eclipse users have no idea that
this feature exists, yet it's wonderful ;-)

We certainly don't want to get flooded with complaints "what's this
new warning here, it's wrong and I can't even turn it off".
Assuming that this warning will have its individual checkbox in
the UI, which is better:
1. user is surprised to see a new warning, can decide to unsubscribe
   if he doesn't like the warning (most users will never notice,
   until some distant date when they first make this mistake).
2. user is unaware of this warning, user is probably also unaware
   that he may occasionally forget a word like throw or return etc.
   Only few users will carefully track the N&N to find this feature,
   so they can explicitly enable. -> Majority is not helped at all.
I'd prefer #1 because I think we're more trying to help the careless
users. The eager ones are better able to help themselves anyway.

my 2c, 
still I'd rather see this adopted with default 'Ignore'
than not adopted at all.

Wasn't it you, Dani,  who insisted that side-effects in ctor are 
BAD STYLE and unused allocation thus has NO justification? ;-)

> - the message should be closer to unused variables:
>   ==> "The allocated object is never used"

OK.
Comment 29 Dani Megert CLA 2009-12-10 08:26:59 EST
>Wasn't it you, Dani,  who insisted that side-effects in ctor are 
>BAD STYLE and unused allocation thus has NO justification? ;-)
Correct but there is nor rule with exceptions. Cases where this is not bad style is for example when creating UI elements like a Label where you really don't care to store it in a variable or when you simply want to validate a URL by creating it and catching the exception.

Another issue is that almost all SDK code base is 1.4 and hence we cannot use @suppressWarnings to silent the cases where the code is intended as is.
Comment 30 Olivier Thomann CLA 2009-12-10 11:58:47 EST
Ok, several small things:
1) If this is part of the unused support I think the category should be:
CategorizedProblem.CAT_UNNECESSARY_CODE and not CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM.

2) Implement comment 27

3) I would like to see a support for the batch compiler with a new warning token.

I am ready to release once this is addressed.

Thanks Stephan for the patch.
Comment 31 Stephan Herrmann CLA 2010-01-12 16:07:30 EST
Created attachment 155923 [details]
patch v3

(In reply to comment #30)
> Ok, several small things:
> 1) If this is part of the unused support I think the category should be:
> CategorizedProblem.CAT_UNNECESSARY_CODE and not
> CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM.

Done.
 
> 2) Implement comment 27

Done, although I'm still not convinced that default=ignore is a good idea.

> 3) I would like to see a support for the batch compiler with a new warning
> token.

Done. (token is "unusedAllocation")

> I am ready to release once this is addressed.

Sorry for the delay.
 
> Thanks Stephan for the patch.

You're welcome ;-)
Comment 32 Olivier Thomann CLA 2010-01-13 09:40:46 EST
Last patch looks good except for the regression tests where we set the corresponding option to ERROR instead of WARNING.
I'll fix that part.
Comment 33 Olivier Thomann CLA 2010-01-13 10:12:09 EST
Released for 3.6M5.
Regression tests added in:
org.eclipse.jdt.core.tests.compiler.regression.FlowAnalysisTest#test063
org.eclipse.jdt.core.tests.compiler.regression.FlowAnalysisTest#test064
org.eclipse.jdt.core.tests.compiler.regression.FlowAnalysisTest#test065
org.eclipse.jdt.core.tests.compiler.regression.FlowAnalysisTest#test066
org.eclipse.jdt.core.tests.compiler.regression.FlowAnalysisTest#test067
org.eclipse.jdt.core.tests.compiler.regression.FlowAnalysisTest#test068

Updated other existing tests.
I also updated the copyrights for the provided patch.
Comment 34 Olivier Thomann CLA 2010-01-13 10:14:17 EST
Created attachment 155983 [details]
Updated patch

This is the patch that ended up being released.
Comment 35 Remy Suen CLA 2010-01-13 10:18:59 EST
Thank you Stephan and Olivier! I'll be turning this on once it's in the build.
:)
Comment 36 Olivier Thomann CLA 2010-01-13 10:25:31 EST
I forgot to mention that unused anonymous class declaration are not detected. I expect this warning to also handle that case.
I'll fix it.
Comment 37 Olivier Thomann CLA 2010-01-13 10:29:00 EST
Created attachment 155987 [details]
Proposed fix for unused anonymous types

Patch released to HEAD
Comment 38 Olivier Thomann CLA 2010-01-13 10:31:57 EST
Created attachment 155989 [details]
Same patch with a regression test
Comment 39 Markus Keller CLA 2010-01-13 13:15:44 EST
(In reply to comment #30)
> 1) If this is part of the unused support I think the category should be:
> CategorizedProblem.CAT_UNNECESSARY_CODE and not
> CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM.

It's good that @SuppressWarnings("unused") works for this problem, but I think it should go back to the CAT_POTENTIAL_PROGRAMMING_PROBLEM category. Up to now, code that was flagged with CAT_UNNECESSARY_CODE could be removed without any semantic change, so it was definitely unnecessary. But unusedObjectAllocation is only a potential problem.
Comment 40 Olivier Thomann CLA 2010-01-13 13:42:40 EST
I missed this subtlety between the two categories. Sorry, Stephan you were right.
I'll fix it.
Comment 41 Olivier Thomann CLA 2010-01-13 14:14:27 EST
Created attachment 156030 [details]
Category change

Category change released in HEAD.
Comment 42 Ayushman Jain CLA 2010-01-25 05:18:15 EST
verified for 3.6M5 using build I20100122-0800
Comment 43 Srikanth Sankaran CLA 2010-01-25 05:25:38 EST
Verified.