Bug 235253 - [organize imports] Organize imports removes needed import statement.
Summary: [organize imports] Organize imports removes needed import statement.
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.4   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.6 M6   Edit
Assignee: Olivier Thomann CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 194358 295638
Blocks:
  Show dependency tree
 
Reported: 2008-06-02 21:13 EDT by Brian Miller CLA
Modified: 2010-03-08 06:04 EST (History)
7 users (show)

See Also:


Attachments
Test cases which show the bug is not reproducible. (4.03 KB, patch)
2009-11-06 11:33 EST, Kelly Campbell CLA
no flags Details | Diff
Proposed fix (1.10 KB, patch)
2009-11-18 12:51 EST, Olivier Thomann CLA
no flags Details | Diff
Proposed fix 2 (8.83 KB, patch)
2010-02-01 10:46 EST, Markus Keller CLA
no flags Details | Diff
Proposed fix + regression tests (20.28 KB, patch)
2010-02-10 14:10 EST, Olivier Thomann CLA
no flags Details | Diff
Proposed fix + regression tests (20.28 KB, patch)
2010-02-10 19:53 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 Brian Miller CLA 2008-06-02 21:13:46 EDT
Build ID: I20080330-1350   (3.4M6)

Steps To Reproduce:
Please organize imports and see that the import statement is wrongly removed, causing a compile error.

In the sample below, I put both classes in the same compilation unit.  But the problem also occurs if in different units.

------------ bug/Bug.java ------------------
package bug;
import bug.Bug.*;
class Bug{
	interface Proto{};
}class Foo implements Proto{}
Comment 1 Martin Aeschlimann CLA 2008-06-03 03:19:03 EDT
I can reproduce it in different compilation units:

package bug;
import bug.Bug.Proto;
class Foo implements Proto{
}

package bug;
class Bug {
        interface Proto{};
}
Comment 2 Martin Aeschlimann CLA 2008-06-09 11:33:00 EDT
I wanted to say: I can NOT reproduce it in different compilation units.
Comment 3 Dani Megert CLA 2009-11-05 03:03:03 EST
Problem in org.eclipse.jdt.core.dom.rewrite.ImportRewrite.
Comment 4 Kelly Campbell CLA 2009-11-06 11:33:39 EST
Created attachment 151581 [details]
Test cases which show the bug is not reproducible.
Comment 5 Brian Miller CLA 2009-11-06 11:42:02 EST
I'm using build 20090920-1017.  Comment 1 isn't reproducible, but the original complaint still is.
Comment 6 Frederic Fusier CLA 2009-11-06 13:26:32 EST
(In reply to comment #4)
> Created an attachment (id=151581) [details]
> Test cases which show the bug is not reproducible.

I had a quick look at your tests and saw that they create two different units... Martin already verified that it's not reproducible when two separated units are used (see comment 2), hence I guess explain why your tests pass.

As Brian also also reproduce it with a recent, build, it is the confirmation that this bug needs to be fixed first and bug 194358 after...
Comment 7 Frederic Fusier CLA 2009-11-13 07:43:19 EST
Closed as fixed as patch for bug 194358 released today (see bug 194358 comment 63) also fixes this bug...
Comment 8 Olivier Thomann CLA 2009-11-16 10:38:32 EST
Reopen as the fix for bug 194358 has been reverted.
Comment 9 Jay Arthanareeswaran CLA 2009-11-17 05:42:12 EST
A better fix would be to fix the org.eclipse.jdt.internal.core.dom.rewrite.ImportRewriteAnalyzer.isImplicitImport(String, ICompilationUnit)

The method doesn't take several points into consideration, such as inner types, whether a particular import is being used or not etc. Especially for the latter, I can't think of a way to do this than passing org.eclipse.jdt.internal.compiler.ast.ASTNode.Used somehow to the ImportRewriteAnalyzer. However, this would mean that we need to resolve the compilation unit and the types, which may have an impact on performance as well. 

Olivier, your thoughts please.
Comment 10 Olivier Thomann CLA 2009-11-18 12:51:54 EST
Created attachment 152493 [details]
Proposed fix

When looking at the test case in comment 0:

package bug;
import bug.Bug.*;
class Bug{
    interface Proto{};
}
class Foo implements Proto{}

The import is needed to be able to resolve the name "Proto" for the class Foo.

The problem in this case is that the ImportRewriteAnalyzer.isImplicitImport is way too simple.
The import is discarded because it matches the "main" qualified type name of the cu.
If you rename your unit "Z.java", you won't see the problem.

Also OrganizeImport is always used with the filtering of implicit imports set to true. This is the bottom of the problem. The decision for an import to be implicit or not *cannot* be made based on its name only. At least when the name matches the "main" type name, this is clearly not enough to make a judgment.

Replacing the isImplicitImport with:
private static boolean isImplicitImport(String qualifier, ICompilationUnit cu) {
	if (JAVA_LANG.equals(qualifier)) {
		return true;
	}
	String packageName= cu.getParent().getElementName();
	return qualifier.equals(packageName);
}
seems to fix this issue.

If I don't have the import, it is properly added. The provided patch goes into this direction.
I haven't run the tests with it. So tests need to be run with this patch to see if this would be enough.

Jay, please use this patch and see if this would work with your previous fix.
Thanks.
Comment 11 Olivier Thomann CLA 2009-11-18 19:57:15 EST
In order to fix this, we need more context inside the ImportRewriteAnalyzer.
The patch attached doesn't consider this import as implicit anymore. But then it is difficult to say that the import is required or not.
Organize import should not propose an import that is not required.
Comment 12 Markus Keller CLA 2009-11-29 14:12:41 EST
> ... we need more context inside the ImportRewriteAnalyzer.

We already have ImportRewriteContext, I think that's good enough. I've fixed
ExtractConstantRefactoring which didn't use the context and thus failed with
the patch from comment 10. But we have many more cases like this, see bug
295638.
Comment 13 Olivier Thomann CLA 2009-12-07 11:08:22 EST
Moving to M5 since it depends on JDT/UI to use the import context.
Comment 14 Olivier Thomann CLA 2010-01-22 10:32:57 EST
Moving to M6 as bug 295638 won't be fixed in time for M5.
Comment 15 Markus Keller CLA 2010-02-01 10:46:18 EST
Created attachment 157791 [details]
Proposed fix 2

Although the fix from comment 10 just fixes the implementation to conform to the spec of ImportRewrite#setFilterImplicitImports(boolean), it requires a lot of changes in JDT UI. Any third-party plug-in that uses ImportRewrite will see similar problems if that patch is released.

Therefore, I'd categorize this as a breaking change, which we should avoid. The attached patch adds API ImportRewrite#setMainTypeTypesAreImplicitImports(boolean) that allows to fix this bug in a non-breaking way. The patch also adjusts Javadocs of existing APIs.

The JDT Core parts can be released at any time -- I'll take care of the UI part once the new API is released. If someone has a better idea for the name of the new property, please speak up.
Comment 16 Olivier Thomann CLA 2010-02-10 14:08:59 EST
This will be released as part of the fix for bug 194358.
Comment 17 Olivier Thomann CLA 2010-02-10 14:10:10 EST
Created attachment 158758 [details]
Proposed fix + regression tests
Comment 18 Olivier Thomann CLA 2010-02-10 19:53:29 EST
Created attachment 158804 [details]
Proposed fix + regression tests
Comment 19 Olivier Thomann CLA 2010-02-10 20:03:28 EST
Released for 3.6M6.
A new API is added to enable a mode where using context allows to better control the imports.
UI changes are required before the fix is visible in the editor and using organize imports.
Comment 20 Thomas Hallgren CLA 2010-02-24 10:37:51 EST
I just tried the I-build from 20100223. When I save a file that has references to Entry (java.util.Map.Entry), the import for that class just vanishes. I.e. of these two:

import java.util.*;
import java.util.Map.Entry;

only the former is left.
Comment 21 Olivier Thomann CLA 2010-02-24 10:49:54 EST
I think this is a bug that is now visible because java.util.Map.Entry is in the same import group as java.util.*;.
In case of reference to member types inside a type in the same package, that entry should not be removed when using import like java.util.*.
I opened bug 303776 to take care of this issue.
Closing as FIXED.
Comment 22 Jay Arthanareeswaran CLA 2010-03-08 06:04:22 EST
Verified for 3.6M6 using build I20100305-1011.