mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
Field can be local: added support for nested and local classes (IDEA-206647)
This commit is contained in:
@@ -69,10 +69,13 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
|
||||
if (candidates.isEmpty()) return;
|
||||
final List<ImplicitUsageProvider> implicitUsageProviders = ImplicitUsageProvider.EP_NAME.getExtensionList();
|
||||
|
||||
PsiClass scope = PsiTreeUtil.getTopmostParentOfType(aClass, PsiClass.class);
|
||||
if (scope == null) scope = aClass;
|
||||
|
||||
FieldLoop:
|
||||
for (final PsiField field : candidates) {
|
||||
if (usedFields.contains(field) && !hasImplicitReadOrWriteUsage(field, implicitUsageProviders)) {
|
||||
final Query<PsiReference> references = ReferencesSearch.search(field, new LocalSearchScope(aClass));
|
||||
final Query<PsiReference> references = ReferencesSearch.search(field, new LocalSearchScope(scope));
|
||||
final Map<PsiCodeBlock, Collection<PsiReference>> refs = new HashMap<>();
|
||||
for (PsiReference reference : references.findAll()) {
|
||||
final PsiElement element = reference.getElement();
|
||||
@@ -151,6 +154,11 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
|
||||
//do not go inside class initializer
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLambdaExpression(PsiLambdaExpression expression) {
|
||||
// do not go inside lambda
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
excludeFieldCandidate(expression);
|
||||
@@ -295,7 +303,7 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
|
||||
|
||||
private static boolean groupReferenceByCodeBlocks(Map<PsiCodeBlock, Collection<PsiReference>> refs, PsiReference psiReference) {
|
||||
final PsiElement element = psiReference.getElement();
|
||||
final PsiCodeBlock block = PsiTreeUtil.getTopmostParentOfType(element, PsiCodeBlock.class);
|
||||
final PsiCodeBlock block = getTopmostBlock(element);
|
||||
if (block == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -310,6 +318,17 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiCodeBlock getTopmostBlock(@NotNull PsiElement element) {
|
||||
PsiElement parent = element.getParent();
|
||||
PsiCodeBlock block = null;
|
||||
while (parent != null && !(parent instanceof PsiClass)) {
|
||||
if (parent instanceof PsiCodeBlock) block = (PsiCodeBlock)parent;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
private static boolean findExistentBlock(Map<PsiCodeBlock, Collection<PsiReference>> refs,
|
||||
PsiReference psiReference,
|
||||
PsiCodeBlock block,
|
||||
@@ -365,8 +384,29 @@ public class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspectionTo
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitJavaFile(PsiJavaFile file) {
|
||||
final JavaElementVisitor visitor = new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
super.visitClass(aClass);
|
||||
Arrays.stream(aClass.getChildren()).forEach(c -> c.accept(this));
|
||||
doCheckClass(aClass, holder, EXCLUDE_ANNOS, IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDeclarationStatement(PsiDeclarationStatement statement) {
|
||||
super.visitDeclarationStatement(statement);
|
||||
Arrays.stream(statement.getDeclaredElements()).forEach(d -> d.accept(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethod(PsiMethod method) {
|
||||
super.visitMethod(method);
|
||||
final PsiCodeBlock body = method.getBody();
|
||||
if (body != null) Arrays.stream(body.getChildren()).forEach(c -> c.accept(this));
|
||||
}
|
||||
};
|
||||
for (PsiClass aClass : file.getClasses()) {
|
||||
doCheckClass(aClass, holder, EXCLUDE_ANNOS, IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS);
|
||||
aClass.accept(visitor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Convert field to local variable in method 'test'" "true"
|
||||
class Foo {
|
||||
void test() {
|
||||
class Bar {
|
||||
|
||||
void test() {
|
||||
int x = 2; // could be local
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// "Convert to local" "true"
|
||||
class Outer {
|
||||
|
||||
void test() {
|
||||
class Local {
|
||||
|
||||
void foo() {
|
||||
String s = "1";
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
void bar() {
|
||||
String s = "2";
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Convert field to local variable in method 'test'" "true"
|
||||
class Foo {
|
||||
static class Bar {
|
||||
|
||||
void test() {
|
||||
int x = 2; // could be local
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// "Convert to local" "true"
|
||||
class Test {
|
||||
|
||||
private Runnable r = () -> {
|
||||
String field = "foo";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// "Fix all 'Field can be local' problems in file" "false"
|
||||
class Outer {
|
||||
|
||||
void test(Inner inner) {
|
||||
System.out.println(inner.field);
|
||||
}
|
||||
|
||||
class Inner {
|
||||
private final String f<caret>ield;
|
||||
|
||||
Inner(String field) {
|
||||
this.field = field;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Convert field to local variable in method 'test'" "true"
|
||||
class Foo {
|
||||
void test() {
|
||||
class Bar {
|
||||
private int <caret>x;
|
||||
|
||||
void test() {
|
||||
x = 2; // could be local
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// "Convert to local" "true"
|
||||
class Outer {
|
||||
|
||||
void test() {
|
||||
class Local {
|
||||
private String <caret>s;
|
||||
|
||||
void foo() {
|
||||
s = "1";
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
void bar() {
|
||||
s = "2";
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Convert field to local variable in method 'test'" "true"
|
||||
class Foo {
|
||||
static class Bar {
|
||||
private int <caret>x;
|
||||
|
||||
void test() {
|
||||
x = 2; // could be local
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Convert to local" "true"
|
||||
class Test {
|
||||
|
||||
private String <caret>field;
|
||||
|
||||
private Runnable r = () -> {
|
||||
field = "foo";
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
private int value = 0;
|
||||
|
||||
public class Inner {
|
||||
private final int myValue;
|
||||
private final int <warning descr="Field can be converted to a local variable">myValue</warning>;
|
||||
|
||||
public Inner() {
|
||||
myValue = value++;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
private int <warning descr="Field can be converted to a local variable">value</warning> = 0;
|
||||
|
||||
public class Inner {
|
||||
private final int myValue;
|
||||
private final int <warning descr="Field can be converted to a local variable">myValue</warning>;
|
||||
|
||||
public Inner() {
|
||||
myValue = value;
|
||||
|
||||
Reference in New Issue
Block a user