Skip to content

Commit af4df79

Browse files
sid-srinilahodaj
andcommitted
Partial handling of module imports
1. Enhanced support for module imports in java.source/CasualDiff to allow re-ordering of imports. 2. Enhanced java.hints/OrganizeImports to support the presence of module imports in checking for usage, and, transferring the module import scope. Also included sort comparison for module imports, adding them as the last group. 3. Enhanced java.source/GeneratorUtilities.addImports() to support the writing of existing module imports in the compilation unit, as well as, the addition of module imports if needed in the future by any hint/completion. This includes: - checking for the usage of a module import. - checking for simple name clashes in the consolidated import scope which includes module imports now, for adding as named imports. - sorting comparison for module imports (added as the last group). 4. Incorporated handling of transitive module imports in partial support - In OrganizeImports and GeneratorUtilities. Note: Uses ElementOverlay.moduleOf when GeneratorUtilities.addImports is invoked from ImmutableTreeTranslator Co-authored-by: Jan Lahoda <[email protected]> Signed-off-by: Siddharth Srinivasan <[email protected]>
1 parent 3860d48 commit af4df79

File tree

9 files changed

+798
-48
lines changed

9 files changed

+798
-48
lines changed

java/java.hints/src/org/netbeans/modules/java/hints/OrganizeImports.java

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,26 @@
2222
import java.awt.event.ActionEvent;
2323
import java.util.Collections;
2424
import java.util.Comparator;
25+
import java.util.HashMap;
2526
import java.util.HashSet;
2627
import java.util.LinkedList;
2728
import java.util.List;
29+
import java.util.Map;
2830
import java.util.Set;
2931
import java.util.concurrent.atomic.AtomicBoolean;
3032

3133
import javax.lang.model.element.Element;
3234
import javax.lang.model.element.Modifier;
35+
import javax.lang.model.element.ModuleElement;
36+
import javax.lang.model.element.PackageElement;
3337
import javax.lang.model.type.TypeKind;
3438
import javax.lang.model.util.Types;
3539
import javax.swing.text.JTextComponent;
3640
import javax.tools.Diagnostic;
3741

3842
import com.sun.source.tree.ClassTree;
3943
import com.sun.source.tree.CompilationUnitTree;
44+
import com.sun.source.tree.ExpressionTree;
4045
import com.sun.source.tree.IdentifierTree;
4146
import com.sun.source.tree.ImportTree;
4247
import com.sun.source.tree.MemberSelectTree;
@@ -80,6 +85,7 @@
8085
import org.netbeans.spi.java.hints.TriggerTreeKind;
8186
import org.openide.util.Exceptions;
8287
import org.openide.util.NbBundle;
88+
import org.openide.util.Pair;
8389

8490
/**
8591
*
@@ -160,10 +166,11 @@ public static void doOrganizeImports(WorkingCopy copy, Set<Element> addImports,
160166
}
161167
}
162168
final CodeStyle cs = CodeStyle.getDefault(copy.getFileObject());
163-
Set<Element> starImports = new HashSet<Element>();
164-
Set<Element> staticStarImports = new HashSet<Element>();
165-
Set<Element> toImport = getUsedElements(copy, cu, starImports, staticStarImports);
166-
List<ImportTree> imps = new LinkedList<ImportTree>();
169+
final Set<Element> starImports = new HashSet<>();
170+
final Set<Element> staticStarImports = new HashSet<>();
171+
final Set<Element> moduleImports = new HashSet<>();
172+
Set<Element> toImport = getUsedElements(copy, cu, starImports, staticStarImports, moduleImports);
173+
final List<ImportTree> imps = new LinkedList<>();
167174
TreeMaker maker = copy.getTreeMaker();
168175

169176
if (addImports != null) {
@@ -173,6 +180,7 @@ public static void doOrganizeImports(WorkingCopy copy, Set<Element> addImports,
173180
} else if (!toImport.isEmpty() || isBulkMode) {
174181
// track import star import scopes, so only one star import/scope appears in imps - #251977
175182
Set<Element> starImportScopes = new HashSet<>();
183+
Map<ModuleElement, Pair<ExpressionTree, ModuleElement>> transitiveScopeToModuleImport = new HashMap<>();
176184
Trees trees = copy.getTrees();
177185
for (ImportTree importTree : cu.getImports()) {
178186
Tree qualIdent = importTree.getQualifiedIdentifier();
@@ -181,13 +189,13 @@ public static void doOrganizeImports(WorkingCopy copy, Set<Element> addImports,
181189
Element importedScope = trees.getElement(TreePath.getPath(cu, ((MemberSelectTree)qualIdent).getExpression()));
182190

183191
if (importTree.isStatic()) {
184-
if (staticStarImports != null &&
192+
if (!staticStarImports.isEmpty() &&
185193
staticStarImports.contains(importedScope) &&
186194
!starImportScopes.contains(importedScope)) {
187195
imp = maker.Import(qualIdent, true);
188196
}
189197
} else {
190-
if (starImports != null &&
198+
if (!starImports.isEmpty() &&
191199
starImports.contains(importedScope) &&
192200
!starImportScopes.contains(importedScope)) {
193201
imp = maker.Import(qualIdent, false);
@@ -197,6 +205,28 @@ public static void doOrganizeImports(WorkingCopy copy, Set<Element> addImports,
197205
starImportScopes.add(importedScope);
198206
imps.add(imp);
199207
}
208+
} else if (importTree.isModule()) {
209+
ModuleElement importedScope = copy.getElements().getModuleElement(qualIdent.toString());
210+
if (qualIdent instanceof ExpressionTree moduleIdentifier) {
211+
if (importedScope == null) {
212+
//do not mark unresolvable element imports as unused
213+
imps.add(maker.ImportModule(moduleIdentifier));
214+
} else if (!moduleImports.isEmpty() && !starImportScopes.contains(importedScope)) {
215+
if (moduleImports.contains(importedScope)) {
216+
imps.add(maker.ImportModule(moduleIdentifier));
217+
starImportScopes.add(importedScope);
218+
} else {
219+
collectTransitivelyUsedModules(importedScope, moduleIdentifier, moduleImports, copy, transitiveScopeToModuleImport);
220+
}
221+
}
222+
}
223+
}
224+
}
225+
// Add any used modules that are only referred by a transitive import
226+
for (Map.Entry<ModuleElement, Pair<ExpressionTree, ModuleElement>> t : transitiveScopeToModuleImport.entrySet()) {
227+
if (!starImportScopes.contains(t.getKey()) && !starImportScopes.contains(t.getValue().second())) {
228+
imps.add(maker.ImportModule(t.getValue().first()));
229+
starImportScopes.add(t.getValue().second());
200230
}
201231
}
202232
} else {
@@ -213,21 +243,42 @@ public int compare(ImportTree o1, ImportTree o2) {
213243
return 0;
214244
String s1 = o1.getQualifiedIdentifier().toString();
215245
String s2 = o2.getQualifiedIdentifier().toString();
216-
int bal = groups.getGroupId(s1, o1.isStatic()) - groups.getGroupId(s2, o2.isStatic());
246+
int bal;
247+
if (o1.isModule()) {
248+
bal = o2.isModule() ? 0 : 1; // Place element imports last
249+
} else if (o2.isModule()) {
250+
bal = -1; // Place element imports last
251+
} else {
252+
bal = groups.getGroupId(s1, o1.isStatic()) - groups.getGroupId(s2, o2.isStatic());
253+
}
217254
return bal == 0 ? s1.compareTo(s2) : bal;
218255
}
219256
});
220257
}
221258
CompilationUnitTree cut = maker.CompilationUnit(cu.getPackageAnnotations(), cu.getPackageName(), imps, cu.getTypeDecls(), cu.getSourceFile());
222259
((JCCompilationUnit)cut).packge = ((JCCompilationUnit)cu).packge;
223-
if (starImports != null || staticStarImports != null) {
224-
((JCCompilationUnit)cut).starImportScope = ((JCCompilationUnit)cu).starImportScope;
260+
((JCCompilationUnit)cut).starImportScope = ((JCCompilationUnit)cu).starImportScope;
261+
if (!moduleImports.isEmpty()) {
262+
((JCCompilationUnit)cut).moduleImportScope = ((JCCompilationUnit)cu).moduleImportScope;
225263
}
226264
CompilationUnitTree ncu = toImport.isEmpty() ? cut : GeneratorUtilities.get(copy).addImports(cut, toImport);
227265
copy.rewrite(cu, ncu);
228266
}
267+
268+
private static void collectTransitivelyUsedModules(final ModuleElement importedModule, final ExpressionTree importIdentifier, final Set<Element> usedModules, final CompilationInfo info, final Map<ModuleElement, Pair<ExpressionTree, ModuleElement>> transitiveModulesToImportingIdentifier) {
269+
if (importedModule != null) {
270+
if (usedModules.contains(importedModule))
271+
return;
272+
Pair<ExpressionTree, ModuleElement> root = Pair.of(importIdentifier, importedModule);
273+
for (PackageElement pack : info.getElementUtilities().transitivelyExportedPackages(importedModule)) {
274+
if ((pack.getEnclosingElement() instanceof ModuleElement transitiveModule) && transitiveModule != importedModule && usedModules.contains(transitiveModule)) {
275+
transitiveModulesToImportingIdentifier.putIfAbsent(transitiveModule, root);
276+
}
277+
}
278+
}
279+
}
229280

230-
private static Set<Element> getUsedElements(final CompilationInfo info, final CompilationUnitTree cut, final Set<Element> starImports, final Set<Element> staticStarImports) {
281+
private static Set<Element> getUsedElements(final CompilationInfo info, final CompilationUnitTree cut, final Set<Element> starImports, final Set<Element> staticStarImports, final Set<Element> moduleImports) {
231282
final Set<Element> ret = new HashSet<Element>();
232283
final Trees trees = info.getTrees();
233284
final Types types = info.getTypes();
@@ -273,7 +324,7 @@ private void addElement(Element element) {
273324
case FIELD:
274325
case METHOD:
275326
if (element.getModifiers().contains(Modifier.STATIC)) {
276-
Element glob = global(element, staticStarImports);
327+
Element glob = global(element, staticStarImports, moduleImports);
277328
if (glob != null)
278329
ret.add(glob);
279330
}
@@ -283,14 +334,14 @@ private void addElement(Element element) {
283334
case RECORD:
284335
case ENUM:
285336
case INTERFACE:
286-
Element glob = global(element, starImports);
337+
Element glob = global(element, starImports, moduleImports);
287338
if (glob != null)
288339
ret.add(glob);
289340
}
290341
}
291342
}
292343

293-
private Element global(Element element, Set<Element> stars) {
344+
private Element global(Element element, Set<Element> stars, Set<Element> modules) {
294345
for (Symbol sym : ((JCCompilationUnit)cut).namedImportScope.getSymbolsByName((Name)element.getSimpleName())) {
295346
if (element == sym || element.asType().getKind() == TypeKind.ERROR && element.getKind() == sym.getKind())
296347
return sym;
@@ -307,6 +358,14 @@ private Element global(Element element, Set<Element> stars) {
307358
return sym;
308359
}
309360
}
361+
for (Symbol sym : ((JCCompilationUnit)cut).moduleImportScope.getSymbolsByName((Name)element.getSimpleName())) {
362+
if (element == sym || element.asType().getKind() == TypeKind.ERROR && element.getKind() == sym.getKind()) {
363+
if (modules != null) {
364+
modules.add(sym.packge().modle);
365+
}
366+
return sym;
367+
}
368+
}
310369
return null;
311370
}
312371
}.scan(cut, null);

0 commit comments

Comments
 (0)