Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,9 @@ HINT_SerialVersionUID_Generated=Add generated serialVersionUID
FieldForUnusedParamCustomizer.finalFields.text=<html>Fields are <code>final</code></html>
ACSD_Final_Fields=Make fields created by this hint final.

DSC_StaticImport=Convert a static method/field/enum-field reference to use a static import. Feedback to <a href="http://www.netbeans.org/issues/show_bug.cgi?id=89258">http://www.netbeans.org/issues/show_bug.cgi?id=89258</a>
DSC_StaticImport=<html>Convert a static method/field/enum-field reference to use a static import.\
<p><code>Math.abs(-1)</code> -> <code>abs(-1)</code></p><html>

DN_StaticImport=Static imports
ERR_StaticImport=Convert to static import
HINT_StaticImport=Convert {0} to static import
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.util.TreePath;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
Expand All @@ -42,7 +41,6 @@
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.api.java.source.ElementUtilities;
import org.netbeans.api.java.source.GeneratorUtilities;
import org.netbeans.api.java.source.TreeMaker;
import org.netbeans.api.java.source.TreePathHandle;
Expand Down Expand Up @@ -77,36 +75,36 @@
*
* @author Sam Halliday
* @author markiewb
* @see <a href="http://www.netbeans.org/issues/show_bug.cgi?id=89258">RFE 89258</a>
* @see <a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/static-import.html>Static Imports</a>
* @see <a href="https://docs.oracle.com/javase/1.5.0/docs/guide/language/static-import.html>Static Imports</a>
*/
@Hint(category="rules15", displayName="#DN_StaticImport", description="#DSC_StaticImport", severity=Severity.HINT, enabled=false, suppressWarnings={"", "StaticImport"},
minSourceVersion = "5")
public class StaticImport {

private static final Set<ElementKind> SUPPORTED_TYPES = EnumSet.of(ElementKind.METHOD, ElementKind.ENUM_CONSTANT, ElementKind.FIELD);

@TriggerTreeKind(Kind.MEMBER_SELECT)
public static List<ErrorDescription> run(HintContext ctx) {
CompilationInfo info = ctx.getInfo();
TreePath treePath = ctx.getPath();

Element e = info.getTrees().getElement(treePath);
EnumSet<ElementKind> supportedTypes = EnumSet.of(ElementKind.METHOD, ElementKind.ENUM_CONSTANT, ElementKind.FIELD);
if (e == null || !e.getModifiers().contains(Modifier.STATIC) || !supportedTypes.contains(e.getKind())) {
if (e == null || !e.getModifiers().contains(Modifier.STATIC) || !SUPPORTED_TYPES.contains(e.getKind())) {
return null;
}

if (ElementKind.METHOD == e.getKind()) {
TreePath mitp = treePath.getParentPath();
if (mitp == null || mitp.getLeaf().getKind() != Kind.METHOD_INVOCATION) {
return null;
}
return null;
}
if (((MethodInvocationTree) mitp.getLeaf()).getMethodSelect() != treePath.getLeaf()) {
return null;
}
return null;
}
List<? extends Tree> typeArgs = ((MethodInvocationTree) mitp.getLeaf()).getTypeArguments();
if (typeArgs != null && !typeArgs.isEmpty()) {
return null;
}
return null;
}
}
Element enclosingEl = e.getEnclosingElement();
if (enclosingEl == null) {
Expand All @@ -122,7 +120,7 @@ public static List<ErrorDescription> run(HintContext ctx) {
return null;
}
Element klass = info.getTrees().getElement(cc);
if (klass == null || klass.getKind() != ElementKind.CLASS) {
if (klass == null || !klass.getKind().isDeclaredType()) {
return null;
}
String fqn = null;
Expand All @@ -143,7 +141,7 @@ public static List<ErrorDescription> run(HintContext ctx) {
if (ctx.isCanceled()) {
return null;
}
return Collections.singletonList(ed);
return List.of(ed);
}

public static final class FixImpl extends JavaFix {
Expand Down Expand Up @@ -189,31 +187,18 @@ protected void performRewrite(TransformationContext ctx) throws Exception {
return;
}
CompilationUnitTree cut = (CompilationUnitTree) copy.resolveRewriteTarget(copy.getCompilationUnit());
CompilationUnitTree nue = GeneratorUtilities.get(copy).addImports(cut, Collections.singleton(e));
CompilationUnitTree nue = GeneratorUtilities.get(copy).addImports(cut, Set.of(e));
copy.rewrite(cut, nue);
}

}

/**
* @param info
* @return true if the source level supports the static import language feature
*/
private static boolean supportsStaticImports(CompilationInfo info) {
return info.getSourceVersion().compareTo(SourceVersion.RELEASE_5) >= 0;
}

// returns true if a METHOD is enclosed in element with simple name sn
private static boolean hasMethodWithSimpleName(CompilationInfo info, Element element, final String sn) {
Iterable<? extends Element> members =
info.getElementUtilities().getMembers(element.asType(), new ElementUtilities.ElementAcceptor() {

@Override
public boolean accept(Element e, TypeMirror type) {
return e.getKind() == ElementKind.METHOD && e.getSimpleName().toString().equals(sn);
}
});
return members.iterator().hasNext();
return info.getElementUtilities().getMembers(
element.asType(),
(elem, type) -> elem.getKind() == ElementKind.METHOD && elem.getSimpleName().toString().equals(sn)
).iterator().hasNext();
}

/**
Expand Down Expand Up @@ -266,7 +251,7 @@ private static boolean hasStaticImportSimpleNameClash(CompilationInfo info, Stri
*/
private static boolean isSubTypeOrInnerOfSubType(CompilationInfo info, Element t1, Element t2) {
boolean isSubtype = info.getTypes().isSubtype(t1.asType(), t2.asType());
boolean isInnerClass = t1.getEnclosingElement().getKind() == ElementKind.CLASS;
boolean isInnerClass = t1.getEnclosingElement().getKind().isDeclaredType();
return isSubtype || (isInnerClass && info.getTypes().isSubtype(t1.getEnclosingElement().asType(), t2.asType()));
}

Expand All @@ -278,15 +263,12 @@ private static boolean isSubTypeOrInnerOfSubType(CompilationInfo info, Element t
* methods in klass (which may be an inner or static class).
*/
private static boolean hasMethodNameClash(CompilationInfo info, Element klass, String simpleName) {
assert klass != null;
assert klass.getKind() == ElementKind.CLASS;

// check the members and inherited members of the klass
if (hasMethodWithSimpleName(info, klass, simpleName)) {
return true;
}
Element klassEnclosing = klass.getEnclosingElement();
return (klassEnclosing != null && klassEnclosing.getKind() == ElementKind.CLASS && hasMethodWithSimpleName(info, klassEnclosing, simpleName));
return klassEnclosing != null && klassEnclosing.getKind().isDeclaredType() && hasMethodWithSimpleName(info, klassEnclosing, simpleName);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ public void testStaticImportHint1() throws Exception {
String golden = "package test; import static java.lang.Math.abs; public class Test { public Test() { abs(1); } }";
performFixTest(test, golden);
}

public void testStaticImportHint1_InRecord() throws Exception {
String test = "package test; public record Test(int n) { public Test { Math.|abs(n); } }";
String golden = "package test; import static java.lang.Math.abs; public record Test(int n) { public Test { abs(n); } }";
performFixTest(test, golden, 17);
}

public void testStaticImportHint2() throws Exception {
String test = "package test; public class Test { public Test() { Test.get|Logger(); } public static void getLogger() { } }";
Expand Down Expand Up @@ -161,17 +167,22 @@ public void testIgnoreClass() throws Exception {
performAnalysisTest(test);
}

private void performFixTest(String test, String golden) throws Exception {
performFixTest(test, golden, 8);
}

// test is single line source code for test.Test, | in the member select, space before
// golden is the output to test against
// sn is the simple name of the static method
private void performFixTest(String test, String golden) throws Exception {
private void performFixTest(String test, String golden, int level) throws Exception {
int offset = test.indexOf("|");
assertTrue(offset != -1);
int end = test.indexOf("(", offset) - 1;
assertTrue(end > 0);
int start = test.lastIndexOf(" ", offset) + 1;
assertTrue(start > 0);
HintTest.create()
.sourceLevel(level)
.input(test.replace("|", ""))
.run(StaticImport.class)
.findWarning("0:" + start + "-0:" + end + ":hint:" + NbBundle.getMessage(StaticImport.class, "ERR_StaticImport"))
Expand Down
Loading