This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 238402 - Incorrect "The assigned value is never used" hint while the value is used in the finally block
Summary: Incorrect "The assigned value is never used" hint while the value is used in ...
Status: RESOLVED FIXED
Alias: None
Product: java
Classification: Unclassified
Component: Hints (show other bugs)
Version: 7.4
Hardware: PC Windows 7 x64
: P2 normal (vote)
Assignee: Svata Dedic
URL:
Keywords:
Depends on:
Blocks: 249320
  Show dependency tree
 
Reported: 2013-11-15 07:10 UTC by cajkovsky
Modified: 2015-11-17 13:07 UTC (History)
0 users

See Also:
Issue Type: ENHANCEMENT
Exception Reporter:


Attachments
A screenshot and a sample NetBeans project to reproduce the bug. (34.27 KB, application/x-zip-compressed)
2013-11-15 07:10 UTC, cajkovsky
Details

Note You need to log in before you can comment on or make changes to this bug.
Description cajkovsky 2013-11-15 07:10:56 UTC
Created attachment 142210 [details]
A screenshot and a sample NetBeans project to reproduce the bug.

The IDE shows an incorrect "The assigned value is never used" hint while the value is actually used in the finally block after an exception is thrown.

A sample code to illustrate the case:

    private void test() {
        int x = 0;
        try {
            x = 1; // <= IDE hint: "The assigned value is never used"
            throwException();
            x = 2;
        } finally {
            System.out.println("x = " + x);
        }
    }
    
    private void throwException() {
        throw new RuntimeException();
    }


A screenshot and a sample NetBeans project is available in the attached archive.
Comment 1 Jiri Prox 2013-11-15 07:58:56 UTC
reproducible
Comment 2 Svata Dedic 2014-01-30 12:50:02 UTC
It seems that identified data flow paths do not include potential abrupt termination of try command in any place because of RuntimException.
Comment 3 Svata Dedic 2015-09-10 14:28:46 UTC
To fix this, the IDE would have o understand that the method throwException never returns normally. Since the IDE (now) does not know, it assumes normal return from throwException which means value of `x' is reassigned again.


I would not say that it is a defect, because in all but very simple cases it's very hard to assess the method always throws - i.e. the method is public - may be overriden, it's hosted on another class - requires nonlocal analysis etc.

In order to fix that, user annotation (something like @AlwaysThrows) would be useful, as well as an index from the flow analysis, which marks methods as @AlwaysThrows when the parser/indexer discovers that case - nonlocal analysis can be reduced to a simple index check.
Comment 4 Svata Dedic 2015-11-11 07:52:48 UTC
Correction. In this situation, an unexpected exception like OOM or LinkageError may be thrown at any time, so it does not matter if the called method itself completes normally or abruptly.

Fixed in experimental impl, wait for umbrella issue to close
Comment 5 cajkovsky 2015-11-17 11:59:22 UTC
(In reply to Svata Dedic from comment #3)
> To fix this, the IDE would have o understand that the method throwException
> never returns normally. Since the IDE (now) does not know, it assumes normal
> return from throwException which means value of `x' is reassigned again.
> 
> 
> I would not say that it is a defect, because in all but very simple cases
> it's very hard to assess the method always throws - i.e. the method is
> public - may be overriden, it's hosted on another class - requires nonlocal
> analysis etc.
> 
> In order to fix that, user annotation (something like @AlwaysThrows) would
> be useful, as well as an index from the flow analysis, which marks methods
> as @AlwaysThrows when the parser/indexer discovers that case - nonlocal
> analysis can be reduced to a simple index check.


It doesn't matter if the "throwException" method throws an exception always or only under certain conditions.
The method always throwing an exception was used just for simplicity. (In fact, I came across the invalid hint in a real-life project.)
In the modified sample below the invalid hint is shown as well, even when the "canThowException" method doesn't always throw an exception:

    private void test() {
        int x = 0;
        try {
            x = 1; // <= Invalid IDE hint: "The assigned value is never used"
            for (int i = 1; i <= 5; ++i) {
                canThrowException(i);
            }
            x = 2;
        } finally {
            System.out.println("x = " + x);
        }
    }
    
    private void canThrowException(int value) {
        if (value > 3)
            throw new RuntimeException();
    }
Comment 6 Svata Dedic 2015-11-17 13:07:48 UTC
I've changed the algorithm so that before each assignment and 'in between' each method invocation (after parameters are evaluated and before return value is used) the analyzer conditionally evaluates Throwable subclasses so:
* the simulation reaches RuntimException/Error handlers, if they are present
* the simulation reaches finally clause bypassing any handlers, if Throwable is not caught

This covers your situation as well as random VM errors. The drawback is ibncreased complexity - many paths of execution, especially if the try { } catch|finally { } modifies variables outside the try block so that multiple interim states can be seen in catch/finally.