add static import if possible

This commit is contained in:
Bas
2009-10-19 12:35:57 +02:00
parent 39d8bc9a52
commit 8cf61b4579
2 changed files with 325 additions and 82 deletions
@@ -26,10 +26,7 @@ import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.psiutils.ClassUtils;
import com.siyeh.ig.psiutils.ComparisonUtils;
import com.siyeh.ig.psiutils.MethodCallUtils;
import com.siyeh.ig.psiutils.TestUtils;
import com.siyeh.ig.psiutils.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -65,7 +62,9 @@ public class SimplifiableJUnitAssertionInspection extends BaseInspection {
throws IncorrectOperationException {
final PsiElement methodNameIdentifier = descriptor.getPsiElement();
final PsiElement parent = methodNameIdentifier.getParent();
assert parent != null;
if (parent == null) {
return;
}
final PsiMethodCallExpression callExpression =
(PsiMethodCallExpression)parent.getParent();
if (isAssertThatCouldBeAssertNull(callExpression)) {
@@ -84,27 +83,21 @@ public class SimplifiableJUnitAssertionInspection extends BaseInspection {
private static void replaceAssertWithFail(
PsiMethodCallExpression callExpression)
throws IncorrectOperationException {
final PsiReferenceExpression methodExpression =
callExpression.getMethodExpression();
final PsiMethod method = (PsiMethod)methodExpression.resolve();
assert method != null;
final PsiParameterList parameterList = method.getParameterList();
final PsiParameter[] parameters = parameterList.getParameters();
final PsiMethod method = callExpression.resolveMethod();
if (method == null) {
return;
}
final PsiExpressionList argumentList =
callExpression.getArgumentList();
final PsiExpression[] arguments = argumentList.getExpressions();
final PsiExpression message;
if (parameters.length == 2) {
if (arguments.length == 2) {
message = arguments[0];
} else {
message = null;
}
@NonNls final StringBuilder newExpression = new StringBuilder();
final PsiMethod containingMethod =
PsiTreeUtil.getParentOfType(callExpression, PsiMethod.class);
if (TestUtils.isJUnit4TestMethod(containingMethod)) {
newExpression.append("org.junit.Assert.");
}
addStaticImportIfPossible(callExpression, "fail", newExpression);
newExpression.append("fail(");
if (message != null) {
newExpression.append(message.getText());
@@ -117,10 +110,10 @@ public class SimplifiableJUnitAssertionInspection extends BaseInspection {
private static void replaceAssertTrueWithAssertEquals(
PsiMethodCallExpression callExpression, Project project)
throws IncorrectOperationException {
final PsiReferenceExpression methodExpression =
callExpression.getMethodExpression();
final PsiMethod method = (PsiMethod)methodExpression.resolve();
assert method != null;
final PsiMethod method = callExpression.resolveMethod();
if (method == null) {
return;
}
final PsiParameterList parameterList = method.getParameterList();
final PsiParameter[] parameters = parameterList.getParameters();
final PsiManager psiManager = callExpression.getManager();
@@ -166,21 +159,18 @@ public class SimplifiableJUnitAssertionInspection extends BaseInspection {
lhs = rhs;
rhs = temp;
}
@NonNls final StringBuilder newExpression = new StringBuilder();
final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(
callExpression, PsiMethod.class);
if (TestUtils.isJUnit4TestMethod(containingMethod)) {
newExpression.append("org.junit.Assert.");
if (lhs == null || rhs == null) {
return;
}
@NonNls final StringBuilder newExpression = new StringBuilder();
addStaticImportIfPossible(callExpression, "assertEquals", newExpression);
newExpression.append("assertEquals(");
if (message != null) {
newExpression.append(message.getText());
newExpression.append(',');
}
assert lhs != null;
newExpression.append(lhs.getText());
newExpression.append(',');
assert rhs != null;
newExpression.append(rhs.getText());
if (isFloatingPoint(lhs) || isFloatingPoint(rhs)) {
newExpression.append(",0.0");
@@ -193,10 +183,10 @@ public class SimplifiableJUnitAssertionInspection extends BaseInspection {
private static void replaceAssertWithAssertNull(
PsiMethodCallExpression callExpression, Project project)
throws IncorrectOperationException {
final PsiReferenceExpression methodExpression =
callExpression.getMethodExpression();
final PsiMethod method = (PsiMethod)methodExpression.resolve();
assert method != null;
final PsiMethod method = callExpression.resolveMethod();
if (method == null) {
return;
}
final PsiParameterList parameterList = method.getParameterList();
final PsiParameter[] parameters = parameterList.getParameters();
final PsiManager psiManager = callExpression.getManager();
@@ -230,18 +220,18 @@ public class SimplifiableJUnitAssertionInspection extends BaseInspection {
rhs = lhs;
}
@NonNls final StringBuilder newExpression = new StringBuilder();
final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(
callExpression, PsiMethod.class);
if (TestUtils.isJUnit4TestMethod(containingMethod)) {
newExpression.append("org.junit.Assert.");
}
final PsiReferenceExpression methodExpression =
callExpression.getMethodExpression();
final String methodName = methodExpression.getReferenceName();
if ("assertFalse".equals(methodName) ^
tokenType.equals(JavaTokenType.NE)) {
newExpression.append("assertNotNull(");
final String memberName;
if ("assertFalse".equals(methodName) ^ tokenType.equals(JavaTokenType.NE)) {
memberName = "assertNotNull";
} else {
newExpression.append("assertNull(");
memberName = "assertNull";
}
addStaticImportIfPossible(callExpression, memberName, newExpression);
newExpression.append(memberName);
newExpression.append('(');
if (message != null) {
newExpression.append(message.getText());
newExpression.append(',');
@@ -255,10 +245,10 @@ public class SimplifiableJUnitAssertionInspection extends BaseInspection {
private static void replaceAssertWithAssertSame(
PsiMethodCallExpression callExpression, Project project)
throws IncorrectOperationException {
final PsiReferenceExpression methodExpression =
callExpression.getMethodExpression();
final PsiMethod method = (PsiMethod)methodExpression.resolve();
assert method != null;
final PsiMethod method = callExpression.resolveMethod();
if (method == null) {
return;
}
final PsiParameterList parameterList = method.getParameterList();
final PsiParameter[] parameters = parameterList.getParameters();
final PsiManager psiManager = callExpression.getManager();
@@ -290,26 +280,29 @@ public class SimplifiableJUnitAssertionInspection extends BaseInspection {
lhs = rhs;
rhs = temp;
}
@NonNls final StringBuilder newExpression = new StringBuilder();
final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(
callExpression, PsiMethod.class);
if (TestUtils.isJUnit4TestMethod(containingMethod)) {
newExpression.append("org.junit.Assert.");
if (rhs == null) {
return;
}
@NonNls final StringBuilder newExpression = new StringBuilder();
final PsiReferenceExpression methodExpression =
callExpression.getMethodExpression();
final String methodName = methodExpression.getReferenceName();
final String memberName;
if ("assertFalse".equals(methodName) ^
tokenType.equals(JavaTokenType.NE)) {
newExpression.append("assertNotSame(");
memberName = "assertNotSame";
} else {
newExpression.append("assertSame(");
memberName = "assertSame";
}
addStaticImportIfPossible(callExpression, memberName, newExpression);
newExpression.append(memberName);
newExpression.append('(');
if (message != null) {
newExpression.append(message.getText());
newExpression.append(',');
}
newExpression.append(lhs.getText());
newExpression.append(',');
assert rhs != null;
newExpression.append(rhs.getText());
newExpression.append(')');
replaceExpressionAndShorten(callExpression,
@@ -319,10 +312,10 @@ public class SimplifiableJUnitAssertionInspection extends BaseInspection {
private static void replaceAssertEqualsWithAssertLiteral(
PsiMethodCallExpression callExpression, Project project)
throws IncorrectOperationException {
final PsiReferenceExpression methodExpression =
callExpression.getMethodExpression();
final PsiMethod method = (PsiMethod)methodExpression.resolve();
assert method != null;
final PsiMethod method = callExpression.resolveMethod();
if (method == null) {
return;
}
final PsiParameterList parameterList = method.getParameterList();
final PsiParameter[] parameters = parameterList.getParameters();
final PsiManager psiManager = callExpression.getManager();
@@ -360,13 +353,9 @@ public class SimplifiableJUnitAssertionInspection extends BaseInspection {
Character.toUpperCase(literalValue.charAt(0)) +
literalValue.substring(1);
@NonNls final StringBuilder newExpression = new StringBuilder();
final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(
callExpression, PsiMethod.class);
if (TestUtils.isJUnit4TestMethod(containingMethod)) {
newExpression.append("org.junit.Assert.");
}
newExpression.append("assert");
newExpression.append(uppercaseLiteralValue);
final String methodName = "assert" + uppercaseLiteralValue;
addStaticImportIfPossible(callExpression, methodName, newExpression);
newExpression.append(methodName);
newExpression.append('(');
if (message != null) {
newExpression.append(message.getText());
@@ -378,6 +367,24 @@ public class SimplifiableJUnitAssertionInspection extends BaseInspection {
newExpression.toString());
}
private static void addStaticImportIfPossible(PsiMethodCallExpression context,
String memberName, StringBuilder out) {
final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(
context, PsiMethod.class);
if (TestUtils.isJUnit4TestMethod(containingMethod)) {
final PsiReferenceExpression methodExpression =
context.getMethodExpression();
if (methodExpression.isQualified() ||
!ImportUtils.nameCanBeStaticallyImported(
"org.junit.Assert", memberName, context)) {
out.append("org.junit.Assert.");
} else {
ImportUtils.addStaticImport(
"org.junit.Assert", memberName, context);
}
}
}
private static boolean isFloatingPoint(PsiExpression expression) {
final PsiType type = expression.getType();
return PsiType.FLOAT.equals(type) || PsiType.DOUBLE.equals(type);
@@ -672,7 +679,7 @@ public class SimplifiableJUnitAssertionInspection extends BaseInspection {
return false;
}
final PsiType type = expression2.getType();
return PsiType.BOOLEAN.equals(type);
return PsiType.BOOLEAN.equals(type);
}
private static boolean isEqualityComparison(PsiExpression expression) {
@@ -15,21 +15,51 @@
*/
package com.siyeh.ig.psiutils;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.openapi.project.Project;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.HardcodedMethodConstants;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class ImportUtils{
private ImportUtils(){
}
public static boolean nameCanBeStaticallyImported(
@NotNull String fqName, @NotNull String memberName, @NotNull PsiElement context) {
final PsiClass containingClass = PsiTreeUtil.getParentOfType(context, PsiClass.class);
if (ClassUtils.isSubclass(containingClass, fqName)) {
return true;
}
final PsiField field = containingClass.findFieldByName(memberName, true);
if (field != null) {
return false;
}
final PsiMethod[] methods = containingClass.findMethodsByName(memberName, true);
if (methods.length > 0) {
return false;
}
if (hasOnDemandImportStaticConflict(fqName, memberName, context, true)) {
return false;
}
if (hasExactImportStaticConflict(fqName, memberName, context)) {
return false;
}
return true;
}
public static boolean nameCanBeImported(@NotNull String fqName,
@NotNull PsiElement context){
final PsiClass containingClass = ClassUtils.getContainingClass(context);
final PsiClass containingClass = PsiTreeUtil.getParentOfType(context, PsiClass.class);
if (containingClass != null) {
if (fqName.equals(containingClass.getQualifiedName())) {
return true;
@@ -87,27 +117,57 @@ public class ImportUtils{
if(imports == null){
return false;
}
final PsiImportStatement[] importStatements = imports
.getImportStatements();
final PsiImportStatement[] importStatements =
imports.getImportStatements();
final int lastDotIndex = fqName.lastIndexOf((int) '.');
final String shortName = fqName.substring(lastDotIndex + 1);
final String dottedShortName = '.' + shortName;
for(final PsiImportStatement importStatement : importStatements){
if(!importStatement.isOnDemand()){
final String importName = importStatement.getQualifiedName();
if (importName == null){
return false;
}
if(!importName.equals(fqName)){
if(importName.endsWith(dottedShortName)){
return true;
}
if (importStatement.isOnDemand()) {
continue;
}
final String importName = importStatement.getQualifiedName();
if (importName == null){
return false;
}
if(!importName.equals(fqName)){
if(importName.endsWith(dottedShortName)){
return true;
}
}
}
return false;
}
private static boolean hasExactImportStaticConflict(String qualifierClass, String memberName,
PsiElement context) {
final PsiFile file = context.getContainingFile();
if (!(file instanceof PsiJavaFile)) {
return false;
}
final PsiJavaFile javaFile = (PsiJavaFile) file;
final PsiImportList importList = javaFile.getImportList();
final PsiImportStaticStatement[] importStaticStatements =
importList.getImportStaticStatements();
for (PsiImportStaticStatement importStaticStatement : importStaticStatements) {
if (importStaticStatement.isOnDemand()) {
continue;
}
final String name = importStaticStatement.getReferenceName();
if (!memberName.equals(name)) {
continue;
}
final PsiJavaCodeReferenceElement importReference =
importStaticStatement.getImportReference();
final PsiElement qualifier = importReference.getQualifier();
final String qualifierText = qualifier.getText();
if (!qualifierClass.equals(qualifierText)) {
return true;
}
}
return false;
}
public static boolean hasOnDemandImportConflict(@NotNull String fqName,
@NotNull PsiJavaFile file){
return hasOnDemandImportConflict(fqName, file, false);
@@ -167,6 +227,47 @@ public class ImportUtils{
return hasJavaLangImportConflict(fqName, file);
}
public static boolean hasOnDemandImportStaticConflict(String fqName, String memberName,
PsiElement context) {
return hasOnDemandImportStaticConflict(fqName, memberName, context, false);
}
private static boolean hasOnDemandImportStaticConflict(String fqName, String memberName,
PsiElement context, boolean strict) {
final PsiFile file = context.getContainingFile();
if (!(file instanceof PsiJavaFile)) {
return false;
}
final PsiJavaFile javaFile = (PsiJavaFile) file;
final PsiImportList importList = javaFile.getImportList();
final PsiImportStaticStatement[] importStaticStatements =
importList.getImportStaticStatements();
for (PsiImportStaticStatement importStaticStatement : importStaticStatements) {
if (!importStaticStatement.isOnDemand()) {
continue;
}
final PsiClass targetClass = importStaticStatement.resolveTargetClass();
final String name = targetClass.getQualifiedName();
if (fqName.equals(name)) {
continue;
}
final PsiField field = targetClass.findFieldByName(memberName, true);
if (field != null) {
if (!strict || memberReferenced(field, javaFile)) {
return true;
}
}
final PsiMethod[] methods = targetClass.findMethodsByName(memberName, true);
if (methods.length > 0) {
if (!strict || membersReferenced(methods, javaFile)) {
return true;
}
}
}
return false;
}
public static boolean hasDefaultImportConflict(String fqName,
PsiJavaFile file) {
final String shortName = ClassUtil.extractClassName(fqName);
@@ -242,9 +343,9 @@ public class ImportUtils{
PsiClass aClass){
final String shortName = ClassUtil.extractClassName(fqName);
if(shortName.equals(aClass.getName())){
if(!fqName.equals(aClass.getQualifiedName())){
return true;
}
if(!fqName.equals(aClass.getQualifiedName())){
return true;
}
}
final PsiClass[] classes = aClass.getInnerClasses();
for (PsiClass innerClass : classes) {
@@ -255,6 +356,142 @@ public class ImportUtils{
return false;
}
public static void addStaticImport(@NotNull String qualifierClass, @NotNull String memberName,
@NotNull PsiElement context)
throws IncorrectOperationException {
final PsiClass containingClass = PsiTreeUtil.getParentOfType(context, PsiClass.class);
if (ClassUtils.isSubclass(containingClass, qualifierClass)) {
return;
}
final PsiFile psiFile = context.getContainingFile();
if (!(psiFile instanceof PsiJavaFile)) {
return;
}
final PsiJavaFile javaFile = (PsiJavaFile)psiFile;
final PsiImportList importList = javaFile.getImportList();
if (importList == null) {
return;
}
final PsiImportStatementBase existingImportStatement =
importList.findSingleImportStatement(memberName);
if (existingImportStatement != null) {
return;
} else {
final PsiImportStaticStatement onDemandImportStatement =
findOnDemandImportStaticStatement(importList, qualifierClass);
if (onDemandImportStatement != null) {
if (!hasOnDemandImportStaticConflict(qualifierClass, memberName, context)) {
return;
}
}
}
final Project project = context.getProject();
final GlobalSearchScope scope = context.getResolveScope();
final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
final PsiClass aClass = psiFacade.findClass(qualifierClass, scope);
if (aClass == null) {
return;
}
final String qualifiedName = aClass.getQualifiedName();
if (qualifiedName == null) {
return;
}
final List<PsiImportStaticStatement> imports =
getMatchingImports(importList, qualifiedName);
final CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(project);
final PsiElementFactory elementFactory = psiFacade.getElementFactory();
if (imports.size() < codeStyleSettings.NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND) {
importList.add(elementFactory.createImportStaticStatement(aClass, memberName));
} else {
for (PsiImportStaticStatement importStatement : imports) {
importStatement.delete();
}
importList.add(elementFactory.createImportStaticStatement(aClass, "*"));
}
}
private static PsiImportStaticStatement findOnDemandImportStaticStatement(
PsiImportList importList, String qualifierClass) {
final PsiImportStaticStatement[] importStaticStatements =
importList.getImportStaticStatements();
for (PsiImportStaticStatement importStaticStatement : importStaticStatements) {
if (!importStaticStatement.isOnDemand()) {
continue;
}
final PsiJavaCodeReferenceElement importReference =
importStaticStatement.getImportReference();
final String text = importReference.getText();
if (qualifierClass.equals(text)) {
return importStaticStatement;
}
}
return null;
}
private static List<PsiImportStaticStatement> getMatchingImports(
@NotNull PsiImportList importList, @NotNull String className){
final List<PsiImportStaticStatement> imports = new ArrayList();
for (PsiImportStaticStatement staticStatement : importList.getImportStaticStatements()) {
final PsiClass psiClass = staticStatement.resolveTargetClass();
if (psiClass == null) {
continue;
}
if (!className.equals(psiClass.getQualifiedName())) {
continue;
}
imports.add(staticStatement);
}
return imports;
}
private static boolean memberReferenced(PsiField field, PsiJavaFile javaFile) {
final MemberReferenceVisitor visitor = new MemberReferenceVisitor(field);
javaFile.accept(visitor);
return visitor.isReferenceFound();
}
private static boolean membersReferenced(PsiMethod[] methods, PsiJavaFile javaFile) {
final MemberReferenceVisitor visitor = new MemberReferenceVisitor(methods);
javaFile.accept(visitor);
return visitor.isReferenceFound();
}
private static class MemberReferenceVisitor extends JavaRecursiveElementVisitor {
private final PsiMember[] members;
private boolean referenceFound = false;
public MemberReferenceVisitor(PsiField field) {
this.members = new PsiMember[]{field};
}
public MemberReferenceVisitor(PsiMethod[] methods) {
this.members = methods;
}
@Override
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
if (referenceFound) {
return;
}
super.visitReferenceElement(reference);
if (reference.isQualified()) {
return;
}
final PsiElement target = reference.resolve();
for (PsiMember member : members) {
if (member.equals(target)) {
referenceFound = true;
return;
}
}
}
public boolean isReferenceFound() {
return referenceFound;
}
}
private static class ClassReferenceVisitor
extends JavaRecursiveElementVisitor{
@@ -268,7 +505,6 @@ public class ImportUtils{
this.fullyQualifiedName = fullyQualifiedName;
}
@Override public void visitReferenceElement(
PsiJavaCodeReferenceElement reference) {
super.visitReferenceElement(reference);