(no message)

This commit is contained in:
Eugene Vigdorchik
2005-03-07 17:27:03 +03:00
parent bce31a17d3
commit 0f598b0e7b
3 changed files with 180 additions and 4 deletions
@@ -1,6 +1,7 @@
package com.intellij.codeInspection.ex;
import com.intellij.codeInspection.InspectionToolProvider;
import com.intellij.codeInspection.varScopeCanBeNarrowed.FieldCanBeLocalInspection;
import com.intellij.codeInspection.dependencyViolation.DependencyViolationInspection;
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.codeInsight.i18n.StringI18nInspection;
@@ -46,8 +47,8 @@ public class StandardInspectionToolsProvider implements InspectionToolProvider,
StringI18nInspection.class,
DependencyViolationInspection.class
};
DependencyViolationInspection.class,
FieldCanBeLocalInspection.class
};
}
}
@@ -0,0 +1,175 @@
package com.intellij.codeInspection.varScopeCanBeNarrowed;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ex.BaseLocalInspectionTool;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.controlFlow.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* @author ven
*/
public class FieldCanBeLocalInspection extends BaseLocalInspectionTool {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.varScopeCanBeNarrowed.FieldCanBeLocalInspection");
public String getGroupDisplayName() {
return "Local Code Analysis";
}
public String getDisplayName() {
return "Field can be local";
}
public String getShortName() {
return "FieldCanBeLocal";
}
public ProblemDescriptor[] checkClass(PsiClass aClass, InspectionManager manager, boolean isOnTheFly) {
PsiManager psiManager = aClass.getManager();
final Set<PsiField> candidates = new LinkedHashSet<PsiField>();
final PsiClass topLevelClass = PsiUtil.getTopLevelClass(aClass);
if (topLevelClass == null) return null;
final PsiField[] fields = aClass.getFields();
NextField:
for (int i = 0; i < fields.length; i++) {
PsiField field = fields[i];
if (field.hasModifierProperty(PsiModifier.PRIVATE)) {
final PsiReference[] refs = psiManager.getSearchHelper().findReferences(field, GlobalSearchScope.allScope(psiManager.getProject()), false);
for (int j = 0; j < refs.length; j++) {
PsiElement element = refs[j].getElement();
while(element != null) {
if (element instanceof PsiMethod) {
candidates.add(field);
continue NextField;
}
element = PsiTreeUtil.getParentOfType(element, PsiMember.class);
}
continue NextField;
}
}
}
topLevelClass.accept(new PsiRecursiveElementVisitor() {
public void visitElement(PsiElement element) {
if (candidates.size() > 0) super.visitElement(element);
}
public void visitMethod(PsiMethod method) {
super.visitMethod(method);
final PsiCodeBlock body = method.getBody();
if (body != null) {
try {
final ControlFlow controlFlow = ControlFlowFactory.getControlFlow(body, AllVariablesControlFlowPolicy.getInstance());
final List<PsiReferenceExpression> readBeforeWrite = ControlFlowUtil.getReadBeforeWrite(controlFlow);
for (Iterator<PsiReferenceExpression> iterator = readBeforeWrite.iterator(); iterator.hasNext();) {
final PsiElement resolved = iterator.next().resolve();
if (resolved instanceof PsiField) {
candidates.remove(resolved);
}
}
}
catch (AnalysisCanceledException e) {
candidates.clear();
}
}
}
});
if (candidates.isEmpty()) return null;
ProblemDescriptor[] result = new ProblemDescriptor[candidates.size()];
int i = 0;
for (Iterator<PsiField> iterator = candidates.iterator(); iterator.hasNext(); i++) {
PsiField field = iterator.next();
final String message = "Field can be converted to one or more local variables.";
result[i] = manager.createProblemDescriptor(field, message, new MyQuickFix(field), ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
}
return result;
}
class MyQuickFix implements LocalQuickFix {
private PsiField myField;
public MyQuickFix(final PsiField field) {
myField = field;
}
public String getName() {
return "Convert to local";
}
public void applyFix(Project project, ProblemDescriptor descriptor) {
PsiManager manager = PsiManager.getInstance(project);
PsiSearchHelper helper = manager.getSearchHelper();
Set<PsiMethod> methodSet = new HashSet<PsiMethod>();
final PsiReference[] allRefs = helper.findReferences(myField, GlobalSearchScope.allScope(project), false);
for (int i = 0; i < allRefs.length; i++) {
PsiReference ref = allRefs[i];
if (ref instanceof PsiReferenceExpression) {
final PsiMethod method = PsiTreeUtil.getParentOfType(((PsiReferenceExpression)ref), PsiMethod.class);
LOG.assertTrue(method != null);
methodSet.add(method);
}
}
for (Iterator<PsiMethod> iterator = methodSet.iterator(); iterator.hasNext();) {
PsiMethod method = iterator.next();
final PsiReference[] refs = helper.findReferences(myField, new LocalSearchScope(method), true);
LOG.assertTrue(refs.length > 0);
PsiCodeBlock anchorBlock = findAnchorBlock(refs);
LOG.assertTrue(anchorBlock != null);
final PsiElementFactory elementFactory = manager.getElementFactory();
final CodeStyleManager styleManager = manager.getCodeStyleManager();
final String propertyName = styleManager.variableNameToPropertyName(myField.getName(), VariableKind.FIELD);
final String localName = styleManager.propertyNameToVariableName(propertyName, VariableKind.LOCAL_VARIABLE);
try {
final PsiDeclarationStatement decl = elementFactory.createVariableDeclarationStatement(localName, myField.getType(), null);
anchorBlock.addAfter(decl, anchorBlock.getLBrace());
final PsiReferenceExpression refExpr = (PsiReferenceExpression)elementFactory.createExpressionFromText(localName, null);
for (int j = 0; j < refs.length; j++) {
PsiReference ref = refs[j];
if (ref instanceof PsiReferenceExpression) {
((PsiReferenceExpression)ref).replace(refExpr);
}
}
myField.delete();
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
}
private PsiCodeBlock findAnchorBlock(final PsiReference[] refs) {
PsiCodeBlock result = null;
for (int i = 0; i < refs.length; i++) {
final PsiElement element = refs[i].getElement();
PsiCodeBlock block = PsiTreeUtil.getParentOfType(element, PsiCodeBlock.class);
if (result == null) {
result = block;
}
else {
final PsiElement commonParent = PsiTreeUtil.findCommonParent(result, block);
result = PsiTreeUtil.getParentOfType(commonParent, PsiCodeBlock.class, false);
}
}
return result;
}
}
}
@@ -26,7 +26,7 @@ public class AllVariablesControlFlowPolicy implements ControlFlowPolicy {
return true;
}
public AllVariablesControlFlowPolicy getInstance() {
public static AllVariablesControlFlowPolicy getInstance() {
return INSTANCE;
}