2 * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.siyeh.ig.junit;
18 import com.intellij.codeInspection.ProblemDescriptor;
19 import com.intellij.openapi.module.Module;
20 import com.intellij.openapi.module.ModuleUtilCore;
21 import com.intellij.openapi.project.Project;
22 import com.intellij.openapi.util.Comparing;
23 import com.intellij.psi.*;
24 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
25 import com.intellij.psi.search.GlobalSearchScope;
26 import com.intellij.psi.util.PsiTreeUtil;
27 import com.intellij.util.IncorrectOperationException;
28 import com.siyeh.InspectionGadgetsBundle;
29 import com.siyeh.ig.BaseInspection;
30 import com.siyeh.ig.BaseInspectionVisitor;
31 import com.siyeh.ig.InspectionGadgetsFix;
32 import org.jetbrains.annotations.NotNull;
33 import org.jetbrains.annotations.Nullable;
35 public class UseOfObsoleteAssertInspection extends BaseInspection {
39 public String getDisplayName() {
40 return InspectionGadgetsBundle.message("usage.of.obsolete.assert.display.name");
45 protected String buildErrorString(Object... infos) {
46 String name = (String)infos[0];
47 return InspectionGadgetsBundle.message("use.of.obsolete.assert.problem.descriptor", name);
51 protected InspectionGadgetsFix buildFix(Object... infos) {
52 return new ReplaceObsoleteAssertsFix();
56 public BaseInspectionVisitor buildVisitor() {
57 return new UseOfObsoleteAssertVisitor();
60 private static class UseOfObsoleteAssertVisitor extends BaseInspectionVisitor {
63 public void visitMethodCallExpression(PsiMethodCallExpression expression) {
64 final Project project = expression.getProject();
65 final Module module = ModuleUtilCore.findModuleForPsiElement(expression);
69 final PsiClass newAssertClass = JavaPsiFacade.getInstance(project)
70 .findClass("org.junit.Assert", GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module));
71 if (newAssertClass == null) {
74 final PsiMethod psiMethod = expression.resolveMethod();
75 if (psiMethod == null || !psiMethod.hasModifierProperty(PsiModifier.STATIC)) {
78 final PsiClass containingClass = psiMethod.getContainingClass();
79 if (containingClass == null) {
82 final String name = containingClass.getQualifiedName();
83 if ("junit.framework.Assert".equals(name) || "junit.framework.TestCase".equals(name)) {
84 registerMethodCallError(expression, name);
89 private static class ReplaceObsoleteAssertsFix extends InspectionGadgetsFix {
91 protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
92 final PsiElement psiElement = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiMethodCallExpression.class);
93 if (psiElement == null) {
96 final PsiClass newAssertClass =
97 JavaPsiFacade.getInstance(project).findClass("org.junit.Assert", GlobalSearchScope.allScope(project));
98 final PsiClass oldAssertClass =
99 JavaPsiFacade.getInstance(project).findClass("junit.framework.Assert", GlobalSearchScope.allScope(project));
101 if (newAssertClass == null) {
104 final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)psiElement;
105 final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
106 final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
107 final PsiElement usedImport = qualifierExpression instanceof PsiReferenceExpression ?
108 ((PsiReferenceExpression)qualifierExpression).advancedResolve(true).getCurrentFileResolveScope() :
109 methodExpression.advancedResolve(true).getCurrentFileResolveScope();
110 final PsiMethod psiMethod = methodCallExpression.resolveMethod();
112 final boolean isImportUnused = isImportBecomeUnused(methodCallExpression, usedImport, psiMethod);
114 PsiImportStaticStatement staticStatement = null;
115 if (qualifierExpression == null) {
116 staticStatement = staticallyImported(oldAssertClass, methodExpression);
119 final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(project);
120 if (staticStatement == null) {
121 methodExpression.setQualifierExpression(JavaPsiFacade.getElementFactory(project).createReferenceExpression(newAssertClass));
123 if (isImportUnused && usedImport instanceof PsiImportStatementBase) {
127 styleManager.shortenClassReferences(methodExpression);
130 if (isImportUnused) {
131 final PsiJavaCodeReferenceElement importReference = staticStatement.getImportReference();
132 if (importReference != null) {
133 if (staticStatement.isOnDemand()) {
134 importReference.bindToElement(newAssertClass);
137 final PsiElement importQExpression = importReference.getQualifier();
138 if (importQExpression instanceof PsiJavaCodeReferenceElement) {
139 ((PsiJavaCodeReferenceElement)importQExpression).bindToElement(newAssertClass);
146 .setQualifierExpression(JavaPsiFacade.getElementFactory(project).createReferenceExpression(newAssertClass));
147 styleManager.shortenClassReferences(methodExpression);
151 //refs can be optimized now but should we really?
152 if (isImportUnused) {
153 for (PsiReference reference : ReferencesSearch.search(newAssertClass, new LocalSearchScope(methodCallExpression.getContainingFile()))) {
154 final PsiElement element = reference.getElement();
155 styleManager.shortenClassReferences(element);
160 private static boolean isImportBecomeUnused(final PsiMethodCallExpression methodCallExpression,
161 final PsiElement usedImport,
162 final PsiMethod psiMethod) {
163 final boolean[] proceed = new boolean[]{true};
164 methodCallExpression.getContainingFile().accept(new JavaRecursiveElementWalkingVisitor() {
166 public void visitElement(PsiElement element) {
168 super.visitElement(element);
173 public void visitMethodCallExpression(PsiMethodCallExpression expression) {
174 super.visitMethodCallExpression(expression);
175 if (expression == methodCallExpression) {
178 final PsiMethod resolved = expression.resolveMethod();
179 if (resolved == psiMethod) {
183 final PsiElement resolveScope =
184 expression.getMethodExpression().advancedResolve(false).getCurrentFileResolveScope();
185 if (resolveScope == usedImport) {
195 private static PsiImportStaticStatement staticallyImported(PsiClass oldAssertClass, PsiReferenceExpression methodExpression) {
196 final String referenceName = methodExpression.getReferenceName();
197 final PsiFile containingFile = methodExpression.getContainingFile();
198 if (!(containingFile instanceof PsiJavaFile)) {
201 final PsiImportList importList = ((PsiJavaFile)containingFile).getImportList();
202 if (importList == null) {
205 final PsiImportStaticStatement[] statements = importList.getImportStaticStatements();
206 for (PsiImportStaticStatement statement : statements) {
207 if (oldAssertClass != statement.resolveTargetClass()) {
210 final String importRefName = statement.getReferenceName();
211 final PsiJavaCodeReferenceElement importReference = statement.getImportReference();
212 if (importReference == null) {
215 if (Comparing.strEqual(importRefName, referenceName)) {
216 final PsiElement qualifier = importReference.getQualifier();
217 if (qualifier instanceof PsiJavaCodeReferenceElement) {
221 else if (importRefName == null) {
230 public String getFamilyName() {
231 return InspectionGadgetsBundle.message("use.of.obsolete.assert.quickfix");