From a450b8beecafb600c8657c2815519d6ef4d6d9e8 Mon Sep 17 00:00:00 2001 From: Bas Date: Fri, 16 Oct 2009 17:14:51 +0200 Subject: [PATCH] IDEADEV-40882 add static imports when needed --- .../ipp/junit/FlipAssertLiteralIntention.java | 20 +- ...ssertEqualsWithAssertLiteralIntention.java | 31 ++- ...ssertLiteralWithAssertEqualsIntention.java | 26 ++- .../com/siyeh/ipp/psiutils/ImportUtils.java | 203 +++++++++++++----- 4 files changed, 209 insertions(+), 71 deletions(-) diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/FlipAssertLiteralIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/FlipAssertLiteralIntention.java index c030a9c63939..a410b867977b 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/FlipAssertLiteralIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/FlipAssertLiteralIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2009 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,23 +15,26 @@ */ package com.siyeh.ipp.junit; -import com.intellij.openapi.util.text.StringUtil; +import com.intellij.codeInsight.AnnotationUtil; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import com.siyeh.IntentionPowerPackBundle; import com.siyeh.ipp.base.MutablyNamedIntention; import com.siyeh.ipp.base.PsiElementPredicate; import com.siyeh.ipp.psiutils.BoolUtils; +import com.siyeh.ipp.psiutils.ImportUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; public class FlipAssertLiteralIntention extends MutablyNamedIntention { + @Override protected String getTextForElement(PsiElement element) { final PsiMethodCallExpression call = (PsiMethodCallExpression)element; final PsiReferenceExpression methodExpression = call.getMethodExpression(); - @NonNls final String fromMethodName = StringUtil.notNullize(methodExpression.getReferenceName()); + @NonNls final String fromMethodName = methodExpression.getReferenceName(); @NonNls final String toMethodName; if ("assertTrue".equals(fromMethodName)) { toMethodName = "assertFalse"; @@ -43,11 +46,12 @@ public class FlipAssertLiteralIntention extends MutablyNamedIntention { fromMethodName, toMethodName); } - @NotNull + @Override @NotNull public PsiElementPredicate getElementPredicate() { return new AssertTrueOrFalsePredicate(); } + @Override public void processIntention(PsiElement element) throws IncorrectOperationException { final PsiMethodCallExpression call = (PsiMethodCallExpression)element; @@ -82,6 +86,14 @@ public class FlipAssertLiteralIntention extends MutablyNamedIntention { args[0].getText() + ',' + BoolUtils.getNegatedExpressionText(arg) + ')'; } + if (qualifier == null) { + final PsiMethod containingMethod = + PsiTreeUtil.getParentOfType(call, PsiMethod.class); + if (containingMethod != null && + AnnotationUtil.isAnnotated(containingMethod, "org.junit.Test", true)) { + ImportUtils.addStaticImport(element, "org.junit.Assert", toMethodName); + } + } replaceExpression(callString, call); } } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertEqualsWithAssertLiteralIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertEqualsWithAssertLiteralIntention.java index 5b287303c8b6..4f80b3d2cfc1 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertEqualsWithAssertLiteralIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertEqualsWithAssertLiteralIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2009 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,19 +15,22 @@ */ package com.siyeh.ipp.junit; +import com.intellij.codeInsight.AnnotationUtil; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import com.siyeh.ipp.base.MutablyNamedIntention; import com.siyeh.ipp.base.PsiElementPredicate; import com.siyeh.IntentionPowerPackBundle; +import com.siyeh.ipp.psiutils.ImportUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NonNls; public class ReplaceAssertEqualsWithAssertLiteralIntention extends MutablyNamedIntention { + @Override protected String getTextForElement(PsiElement element) { - final PsiMethodCallExpression call = (PsiMethodCallExpression)element; final PsiExpressionList argumentList = call.getArgumentList(); final PsiExpression[] args = argumentList.getExpressions(); @@ -44,11 +47,12 @@ public class ReplaceAssertEqualsWithAssertLiteralIntention assertString); } - @NotNull + @Override @NotNull public PsiElementPredicate getElementPredicate() { return new AssertEqualsWithLiteralPredicate(); } + @Override public void processIntention(PsiElement element) throws IncorrectOperationException { final PsiMethodCallExpression call = @@ -64,6 +68,7 @@ public class ReplaceAssertEqualsWithAssertLiteralIntention final PsiExpressionList argumentList = call.getArgumentList(); final PsiExpression[] args = argumentList.getExpressions(); final String callString; + final String assertString; if (args.length == 2) { @NonNls final String argText = args[0].getText(); final PsiExpression otherArg; @@ -74,7 +79,8 @@ public class ReplaceAssertEqualsWithAssertLiteralIntention } else { otherArg = args[0]; } - callString = qualifierText + getAssertString(argText) + '(' + + assertString = getAssertString(argText); + callString = qualifierText + assertString + '(' + otherArg.getText() + ')'; } else { @NonNls final String argText = args[1].getText(); @@ -86,18 +92,27 @@ public class ReplaceAssertEqualsWithAssertLiteralIntention } else { otherArg = args[1]; } - callString = qualifierText + getAssertString(argText) + '(' + + assertString = getAssertString(argText); + callString = qualifierText + assertString + '(' + args[0].getText() + ", " + otherArg.getText() + ')'; } + if (qualifier == null) { + final PsiMethod containingMethod = + PsiTreeUtil.getParentOfType(call, PsiMethod.class); + if (containingMethod != null && + AnnotationUtil.isAnnotated(containingMethod, "org.junit.Test", true)) { + ImportUtils.addStaticImport(element, "org.junit.Assert", assertString); + } + } replaceExpression(callString, call); } @NonNls - private static String getAssertString(@NonNls String argText) { - if ("true".equals(argText)) { + private static String getAssertString(@NonNls String text) { + if ("true".equals(text)) { return "assertTrue"; } - if ("false".equals(argText)) { + if ("false".equals(text)) { return "assertFalse"; } return "assertNull"; diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertLiteralWithAssertEqualsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertLiteralWithAssertEqualsIntention.java index d7ef5e3040e8..8779b24fd998 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertLiteralWithAssertEqualsIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/ReplaceAssertLiteralWithAssertEqualsIntention.java @@ -15,14 +15,17 @@ */ package com.siyeh.ipp.junit; +import com.intellij.codeInsight.AnnotationUtil; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; +import com.siyeh.IntentionPowerPackBundle; import com.siyeh.ipp.base.MutablyNamedIntention; import com.siyeh.ipp.base.PsiElementPredicate; -import com.siyeh.IntentionPowerPackBundle; -import org.jetbrains.annotations.NotNull; +import com.siyeh.ipp.psiutils.ImportUtils; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; public class ReplaceAssertLiteralWithAssertEqualsIntention extends MutablyNamedIntention { @@ -73,17 +76,24 @@ public class ReplaceAssertLiteralWithAssertEqualsIntention @Override public void processIntention(@NotNull PsiElement element) throws IncorrectOperationException { - final PsiMethodCallExpression call = - (PsiMethodCallExpression)element; - final PsiReferenceExpression methodExpression = - call.getMethodExpression(); - final PsiElement qualifier = methodExpression.getQualifier(); + final PsiMethodCallExpression call = (PsiMethodCallExpression)element; + final PsiReferenceExpression methodExpression = call.getMethodExpression(); @NonNls final String methodName = methodExpression.getReferenceName(); - assert methodName != null; + if (methodName == null) { + return; + } final StringBuilder newExpression = new StringBuilder(); + final PsiElement qualifier = methodExpression.getQualifier(); if (qualifier != null) { newExpression.append(qualifier.getText()); newExpression.append('.'); + } else { + final PsiMethod containingMethod = + PsiTreeUtil.getParentOfType(call, PsiMethod.class); + if (containingMethod != null && + AnnotationUtil.isAnnotated(containingMethod, "org.junit.Test", true)) { + ImportUtils.addStaticImport(element, "org.junit.Assert", "assertEquals"); + } } newExpression.append("assertEquals("); final String postfix = methodName.substring("assert".length()); diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ImportUtils.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ImportUtils.java index a478992ee297..ee4d7e86ac6c 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ImportUtils.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/psiutils/ImportUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2006 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2009 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,53 @@ package com.siyeh.ipp.psiutils; import com.intellij.psi.*; -import com.intellij.psi.jsp.JspFile; +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 org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; public class ImportUtils{ private ImportUtils(){ - super(); } public static boolean nameCanBeImported(@NotNull String fqName, - @NotNull PsiJavaFile file){ - if (file instanceof JspFile) return false; + @NotNull PsiElement context){ + final PsiClass containingClass = PsiTreeUtil.getParentOfType(context, PsiClass.class); + if (containingClass != null) { + if (fqName.equals(containingClass.getQualifiedName())) { + return true; + } + final String shortName = ClassUtil.extractClassName(fqName); + final PsiClass[] innerClasses = containingClass.getAllInnerClasses(); + for (PsiClass innerClass : innerClasses) { + if (innerClass.hasModifierProperty(PsiModifier.PRIVATE)) { + continue; + } + if (innerClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) { + if (!inSamePackage(innerClass, containingClass)) { + continue; + } + } + final String className = innerClass.getName(); + if (shortName.equals(className)) { + return false; + } + } + } + final PsiJavaFile file = + PsiTreeUtil.getParentOfType(context, PsiJavaFile.class); + if (file == null) { + return false; + } if(hasExactImportConflict(fqName, file)){ return false; } @@ -41,6 +75,28 @@ public class ImportUtils{ return !containsConflictingClassName(fqName, file); } + public static boolean inSamePackage(@Nullable PsiElement element1, + @Nullable PsiElement element2) { + if (element1 == null || element2==null) { + return false; + } + final PsiFile containingFile1 = element1.getContainingFile(); + if (!(containingFile1 instanceof PsiClassOwner)) { + return false; + } + final PsiClassOwner containingJavaFile1 = + (PsiClassOwner)containingFile1; + final String packageName1 = containingJavaFile1.getPackageName(); + final PsiFile containingFile2 = element2.getContainingFile(); + if (!(containingFile2 instanceof PsiClassOwner)) { + return false; + } + final PsiClassOwner containingJavaFile2 = + (PsiClassOwner)containingFile2; + final String packageName2 = containingJavaFile2.getPackageName(); + return packageName1.equals(packageName2); + } + private static boolean containsConflictingClassName(String fqName, PsiJavaFile file){ final int lastDotIndex = fqName.lastIndexOf((int) '.'); @@ -101,8 +157,7 @@ public class ImportUtils{ } final PsiImportStatement[] importStatements = imports.getImportStatements(); - final int lastDotIndex = fqName.lastIndexOf((int) '.'); - final String shortName = fqName.substring(lastDotIndex + 1); + final String shortName = ClassUtil.extractClassName(fqName); final String packageName = ClassUtil.extractPackageName(fqName); for(final PsiImportStatement importStatement : importStatements){ if (!importStatement.isOnDemand()) { @@ -131,16 +186,13 @@ public class ImportUtils{ if (!strict) { return true; } - final String qualifiedClassname = aClass.getQualifiedName(); + final String qualifiedClassName = aClass.getQualifiedName(); final ClassReferenceVisitor visitor = - new ClassReferenceVisitor(qualifiedClassname); + new ClassReferenceVisitor(qualifiedClassName); file.accept(visitor); return visitor.isReferenceFound(); } } - if (hasDefaultImportConflict(fqName, file)) { - return true; - } return hasJavaLangImportConflict(fqName, file); } @@ -148,18 +200,22 @@ public class ImportUtils{ PsiJavaFile file) { final String shortName = ClassUtil.extractClassName(fqName); final String packageName = ClassUtil.extractPackageName(fqName); - final PsiManager manager = file.getManager(); final String filePackageName = file.getPackageName(); - if(!filePackageName.equals(packageName)){ - final PsiPackage filePackage = JavaPsiFacade.getInstance(manager.getProject()).findPackage(filePackageName); - if(filePackage != null){ - final PsiClass[] classes = filePackage.getClasses(); - for (PsiClass aClass : classes) { - final String className = aClass.getName(); - if(shortName.equals(className)){ - return true; - } - } + if (filePackageName.equals(packageName)) { + return false; + } + final Project project = file.getProject(); + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); + final PsiPackage filePackage = + psiFacade.findPackage(filePackageName); + if (filePackage == null) { + return false; + } + final PsiClass[] classes = filePackage.getClasses(); + for (PsiClass aClass : classes) { + final String className = aClass.getName(); + if(shortName.equals(className)){ + return true; } } return false; @@ -167,20 +223,22 @@ public class ImportUtils{ public static boolean hasJavaLangImportConflict(String fqName, PsiJavaFile file) { - final PsiManager manager = file.getManager(); final String shortName = ClassUtil.extractClassName(fqName); final String packageName = ClassUtil.extractPackageName(fqName); - if(!"java.lang".equals(packageName)){ - final PsiPackage javaLangPackage = JavaPsiFacade.getInstance(manager.getProject()).findPackage("java.lang"); - if(javaLangPackage == null){ - return false; - } - final PsiClass[] classes = javaLangPackage.getClasses(); - for(final PsiClass aClass : classes){ - final String className = aClass.getName(); - if(shortName.equals(className)){ - return true; - } + if ("java.lang".equals(packageName)) { + return false; + } + final Project project = file.getProject(); + final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); + final PsiPackage javaLangPackage = psiFacade.findPackage("java.lang"); + if(javaLangPackage == null){ + return false; + } + final PsiClass[] classes = javaLangPackage.getClasses(); + for(final PsiClass aClass : classes){ + final String className = aClass.getName(); + if(shortName.equals(className)){ + return true; } } return false; @@ -194,6 +252,7 @@ public class ImportUtils{ return true; } } + //return false; final ClassReferenceVisitor visitor = new ClassReferenceVisitor(fqName); file.accept(visitor); @@ -224,17 +283,61 @@ public class ImportUtils{ return false; } - public static boolean importStatementMatches( - PsiImportStatement importStatement, String name){ - final String qualifiedName = importStatement.getQualifiedName(); - - if(importStatement.isOnDemand()){ - final int lastDotIndex = name.lastIndexOf((int) '.'); - final String packageName = name.substring(0, lastDotIndex); - return packageName.equals(qualifiedName); - } else{ - return name.equals(qualifiedName); + public static void addStaticImport(PsiElement context, String qualifierClass, String memberName) + throws IncorrectOperationException { + final PsiFile psiFile = context.getContainingFile(); + if (!(psiFile instanceof PsiJavaFile)) { + 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 PsiJavaFile javaFile = (PsiJavaFile)psiFile; + final PsiImportList importList = javaFile.getImportList(); + if (importList == null) { + return; + } + final String qualifiedName = aClass.getQualifiedName(); + if (qualifiedName == null) { + return; + } + final List imports = + getImportsFromClass(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 (PsiJavaCodeReferenceElement ref : imports) { + final PsiImportStaticStatement importStatement = + PsiTreeUtil.getParentOfType(ref, PsiImportStaticStatement.class); + if (importStatement != null) { + importStatement.delete(); + } + } + importList.add(elementFactory.createImportStaticStatement(aClass, "*")); + } + } + + private static List getImportsFromClass( + @NotNull PsiImportList importList, @NotNull String className){ + final List 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.getImportReference()); + } + return imports; } private static class ClassReferenceVisitor @@ -262,17 +365,15 @@ public class ImportUtils{ } final PsiElement element = reference.resolve(); if (!(element instanceof PsiClass) - || element instanceof PsiTypeParameter) { + || element instanceof PsiTypeParameter) { return; } final PsiClass aClass = (PsiClass) element; final String testClassName = aClass.getName(); final String testClassQualifiedName = aClass.getQualifiedName(); - if (testClassQualifiedName == null || testClassName == null) { - return; - } - if (testClassQualifiedName.equals(fullyQualifiedName) || - !testClassName.equals(m_name)) { + if (testClassQualifiedName == null || testClassName == null + || testClassQualifiedName.equals(fullyQualifiedName) || + !testClassName.equals(m_name)) { return; } m_referenceFound = true;