diff --git a/plugins/InspectionGadgets/Leftovers.txt b/plugins/InspectionGadgets/Leftovers.txt new file mode 100644 index 000000000000..286e3def5594 --- /dev/null +++ b/plugins/InspectionGadgets/Leftovers.txt @@ -0,0 +1,22 @@ + Query string should be constant + Reuse of local variable. + Logging not wrapped in if block + Public method without logging + Logger constructed without the current class name as argument. + Class initialization circularity + Incorrect lazy initialization of static field + setter or getter with non-standard name + Avoid repeated casting + arithmetic operations on volatile types + Field has setter but no getter + Name with forbidden component + Paired open/close for Sockets + Paired open/close for Channels + Paired acquire/release for Locks + + Inheritance as type def (change the EmptyClass inspection) + changing multiply/divide to shift may change precedence! + Fix the "variable accessed in synchronized and unsynchronized contexts" to deal + with unsynchronized private methods called only from synchronized contexts + SerialVersionUID calculation + diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/InstanceofChainInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/InstanceofChainInspection.java new file mode 100644 index 000000000000..52d953afbdd1 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/abstraction/InstanceofChainInspection.java @@ -0,0 +1,89 @@ +package com.siyeh.ig.abstraction; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class InstanceofChainInspection extends StatementInspection { + + public String getDisplayName() { + return "Chain of 'instanceof' checks"; + } + + public String getGroupDisplayName() { + return GroupNames.ABSTRACTION_GROUP_NAME; + } + + protected String buildErrorString(PsiElement location) { + return "Chain of 'instanceof' checks indicates abstraction faiulre #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new InstanceofChainVisitor(this, inspectionManager, onTheFly); + } + + private static class InstanceofChainVisitor extends BaseInspectionVisitor { + private InstanceofChainVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitIfStatement(PsiIfStatement statement) { + super.visitIfStatement(statement); + final PsiElement parent = statement.getParent(); + if (parent instanceof PsiIfStatement) { + final PsiIfStatement parentStatement = (PsiIfStatement) parent; + final PsiStatement elseBranch = parentStatement.getElseBranch(); + if (statement.equals(elseBranch)) { + return; + } + } + int numChecks = 0; + PsiIfStatement branch = statement; + while (branch != null) { + final PsiExpression condition = branch.getCondition(); + if (!isInstanceofCheck(condition)) { + return; + } + numChecks++; + + final PsiStatement elseBranch = branch.getElseBranch(); + if (elseBranch instanceof PsiIfStatement) { + branch = (PsiIfStatement) elseBranch; + } else { + branch = null; + } + } + if (numChecks < 2) { + return; + } + registerStatementError(statement); + } + + private boolean isInstanceofCheck(PsiExpression condition) { + if (condition == null) { + return false; + } else if (condition instanceof PsiInstanceOfExpression) { + return true; + } else if (condition instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression) condition; + final PsiExpression lhs = binaryExpression.getLOperand(); + final PsiExpression rhs = binaryExpression.getROperand(); + return isInstanceofCheck(lhs) && isInstanceofCheck(rhs); + } else if (condition instanceof PsiParenthesizedExpression) { + final PsiExpression contents = ((PsiParenthesizedExpression) condition).getExpression(); + return isInstanceofCheck(contents); + } else if (condition instanceof PsiPrefixExpression) { + final PsiExpression contents = ((PsiPrefixExpression) condition).getOperand(); + return isInstanceofCheck(contents); + } else if (condition instanceof PsiPostfixExpression) { + final PsiExpression contents = ((PsiPostfixExpression) condition).getOperand(); + return isInstanceofCheck(contents); + } + return false; + } + + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/StaticCallOnSubclassInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/StaticCallOnSubclassInspection.java new file mode 100644 index 000000000000..a82e3cd49081 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/bugs/StaticCallOnSubclassInspection.java @@ -0,0 +1,92 @@ +package com.siyeh.ig.bugs; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.psi.*; +import com.intellij.openapi.project.Project; +import com.siyeh.ig.*; + +public class StaticCallOnSubclassInspection extends ExpressionInspection { + private final StaticCallOnSubclassFix fix = new StaticCallOnSubclassFix(); + + + public String getDisplayName() { + return "Static method referenced via subclass"; + } + + public String getGroupDisplayName() { + return GroupNames.BUGS_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiMethodCallExpression methodCall = (PsiMethodCallExpression) location.getParent().getParent(); + final PsiMethod method = methodCall.resolveMethod(); + final String declaringClass = method.getContainingClass().getName(); + final String referencedClass = methodCall.getMethodExpression().getQualifier().getText(); + return "Static method '#ref' declared on class " + declaringClass + " but referenced via class" + referencedClass + " #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class StaticCallOnSubclassFix extends InspectionGadgetsFix { + public String getName() { + return "Rationalize static method call"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiIdentifier name = (PsiIdentifier) descriptor.getPsiElement(); + final PsiReferenceExpression expression = (PsiReferenceExpression) name.getParent(); + final PsiMethodCallExpression call = (PsiMethodCallExpression) expression.getParent(); + final PsiMethod method = call.resolveMethod(); + final String methodName = expression.getReferenceName(); + final PsiClass containingClass = method.getContainingClass(); + final PsiExpressionList argumentList = call.getArgumentList(); + final PsiExpression[] args = argumentList.getExpressions(); + final String argText = args[0].getText(); + replaceExpression(project, call, containingClass.getName() + '.' + methodName + "(" + argText + ")"); + } + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StaticCallOnSubclassVisitor(this, inspectionManager, onTheFly); + } + + private static class StaticCallOnSubclassVisitor extends BaseInspectionVisitor { + private StaticCallOnSubclassVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression call) { + super.visitMethodCallExpression(call); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + if (methodExpression == null) { + return; + } + final PsiElement qualifier = methodExpression.getQualifier(); + if (!(qualifier instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReference) qualifier).resolve(); + if (!(referent instanceof PsiClass)) { + return; + } + final PsiClass referencedClass = (PsiClass) referent; + final PsiMethod method = call.resolveMethod(); + if (method == null) { + return; + } + + final PsiClass declaringClass = method.getContainingClass(); + if (declaringClass.equals(referencedClass)) { + return; + } + registerMethodCallError(call); + + } + + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/UseOfAnotherObjectsPrivateFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/UseOfAnotherObjectsPrivateFieldInspection.java new file mode 100644 index 000000000000..3d0e376801a2 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/encapsulation/UseOfAnotherObjectsPrivateFieldInspection.java @@ -0,0 +1,61 @@ +package com.siyeh.ig.encapsulation; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class UseOfAnotherObjectsPrivateFieldInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Accessing a non-public field of another object"; + } + + public String getGroupDisplayName() { + return GroupNames.ENCAPSULATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Direct access of non-public field #ref on another object #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UseOfAnotherObjectsPrivateFieldVisitor(this, inspectionManager, onTheFly); + } + + private static class UseOfAnotherObjectsPrivateFieldVisitor extends BaseInspectionVisitor { + private UseOfAnotherObjectsPrivateFieldVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitReferenceExpression(PsiReferenceExpression expression) { + super.visitReferenceExpression(expression); + final PsiExpression qualifier = expression.getQualifierExpression(); + if(qualifier == null || qualifier instanceof PsiThisExpression) + { + return; + } + final PsiElement referent = expression.resolve(); + if(referent == null) + { + return; + } + if(!(referent instanceof PsiField)) + { + return; + } + final PsiField field = (PsiField)referent; + if(!field.hasModifierProperty(PsiModifier.PRIVATE) && + !field.hasModifierProperty(PsiModifier.PROTECTED)) + { + return; + } + final PsiElement fieldNameElement = expression.getReferenceNameElement(); + registerError(fieldNameElement); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionCaught.form b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionCaught.form new file mode 100644 index 000000000000..c4ce2ade728a --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionCaught.form @@ -0,0 +1,46 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionCaughtInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionCaughtInspection.java new file mode 100644 index 000000000000..ed016cef39e5 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionCaughtInspection.java @@ -0,0 +1,201 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.WriteExternalException; +import com.intellij.psi.*; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.border.EtchedBorder; +import javax.swing.table.AbstractTableModel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +public class BadExceptionCaughtInspection extends ExpressionInspection { + public String exceptionCheckString = + "java.lang.NullPointerException," + + "java.lang.IllegalMonitorStateException," + + "java.lang.ArrayOutOfBoundsException"; + + private List exceptionsList = new ArrayList(32); + + { + parseExceptionsString(); + } + + public void readSettings(Element element) throws InvalidDataException { + super.readSettings(element); + parseExceptionsString(); + } + + private void parseExceptionsString() { + exceptionsList.clear(); + final String[] strings = exceptionCheckString.split(","); + for (int i = 0; i < strings.length; i++ ) { + exceptionsList.add(strings[i]); + } + } + + public void writeSettings(Element element) throws WriteExternalException { + formatCallCheckString(); + super.writeSettings(element); + } + + private void formatCallCheckString() { + final StringBuffer buffer = new StringBuffer(); + boolean first = true; + for (Iterator iterator = exceptionsList.iterator(); iterator.hasNext();) { + if (first) { + first = false; + } else { + buffer.append(','); + } + final String exceptionName = (String) iterator.next(); + buffer.append(exceptionName); + } + exceptionCheckString = buffer.toString(); + } + + public String getDisplayName() { + return "Prohibitted exception caught"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public JComponent createOptionsPanel() { + final Form form = new Form(); + return form.getContentPanel(); + } + + public String buildErrorString(PsiElement location) { + return "Prohibitted exception '#ref' caught. #loc "; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new BadExceptionCaughtVisitor(this, inspectionManager, onTheFly); + } + + private class BadExceptionCaughtVisitor extends BaseInspectionVisitor { + private BadExceptionCaughtVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitTryStatement(PsiTryStatement statement) { + + super.visitTryStatement(statement); + final PsiParameter[] catchBlockParameters = statement.getCatchBlockParameters(); + for (int i = 0; i < catchBlockParameters.length; i++) { + final PsiParameter parameter = catchBlockParameters[i]; + if(parameter == null) + { + continue; + } + final PsiType type = parameter.getType(); + if(type == null) + { + continue; + } + final String text = type.getCanonicalText(); + if(text == null) + { + continue; + } + for (Iterator iterator = exceptionsList.iterator(); iterator.hasNext();) { + final String exceptionClass = (String) iterator.next(); + if (text.equals(exceptionClass)) { + final PsiTypeElement typeElement = parameter.getTypeElement(); + registerError(typeElement); + continue; + } + } + } + + } + + + } + + public class Form { + private JPanel contentPanel; + private JButton addButton; + private JButton deleteButton; + private JTable table; + + public Form() { + super(); + table.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); + table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + table.setRowSelectionAllowed(true); + table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + table.setEnabled(true); + final ReturnCheckSpecificationTableModel model = + new ReturnCheckSpecificationTableModel(); + table.setModel(model); + addButton.setEnabled(true); + addButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + exceptionsList.add(""); + model.fireTableStructureChanged(); + } + }); + deleteButton.setEnabled(true); + deleteButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + final int[] selectedRows = table.getSelectedRows(); + Arrays.sort(selectedRows); + for (int i = selectedRows.length - 1; i >= 0; i--) { + exceptionsList.remove(selectedRows[i]); + } + model.fireTableStructureChanged(); + } + }); + } + + public JComponent getContentPanel() { + return contentPanel; + } + } + + private class ReturnCheckSpecificationTableModel extends AbstractTableModel { + + public int getRowCount() { + return exceptionsList.size(); + } + + public int getColumnCount() { + return 1; + } + + public String getColumnName(int columnIndex) { + return "Exception class"; + } + + public Class getColumnClass(int columnIndex) { + return String.class; + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return true; + } + + public Object getValueAt(int rowIndex, int columnIndex) { + return exceptionsList.get(rowIndex); + } + + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + exceptionsList.set(rowIndex, aValue); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionDeclared.form b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionDeclared.form new file mode 100644 index 000000000000..0d8cc37735d4 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionDeclared.form @@ -0,0 +1,46 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionDeclaredInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionDeclaredInspection.java new file mode 100644 index 000000000000..696b87527a18 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionDeclaredInspection.java @@ -0,0 +1,201 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.WriteExternalException; +import com.intellij.psi.*; +import com.siyeh.ig.*; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.border.EtchedBorder; +import javax.swing.table.AbstractTableModel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +public class BadExceptionDeclaredInspection extends MethodInspection { + public String exceptionCheckString = "java.lang.Throwable," + + "java.lang.Exception," + + "java.lang.Error," + + "java.lang.RuntimeException," + + "java.lang.NullPointerException," + + "java.lang.ClassCastException," + + "java.lang.ArrayOutOfBoundsException"; + + private List exceptionsList = new ArrayList(32); + + { + parseCallCheckString(); + } + + public void readSettings(Element element) throws InvalidDataException { + super.readSettings(element); + parseCallCheckString(); + } + + private void parseCallCheckString() { + exceptionsList.clear(); + final String[] strings = exceptionCheckString.split(","); + for (int i = 0; i < strings.length; i++ ) { + exceptionsList.add(strings[i]); + } + } + + public void writeSettings(Element element) throws WriteExternalException { + formatCallCheckString(); + super.writeSettings(element); + } + + private void formatCallCheckString() { + final StringBuffer buffer = new StringBuffer(); + boolean first = true; + for (Iterator iterator = exceptionsList.iterator(); iterator.hasNext();) { + if (first) { + first = false; + } else { + buffer.append(','); + } + final String exceptionName = (String) iterator.next(); + buffer.append(exceptionName); + } + exceptionCheckString = buffer.toString(); + } + + public String getDisplayName() { + return "Prohibitted exception declared"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public JComponent createOptionsPanel() { + final Form form = new Form(); + return form.getContentPanel(); + } + + public String buildErrorString(PsiElement location) { + final PsiThrowStatement throwStatement = (PsiThrowStatement) location.getParent(); + final PsiExpression exception = throwStatement.getException(); + final PsiType type = exception.getType(); + final String exceptionName = type.getPresentableText(); + return "Prohibitted exception '" + exceptionName + "' declared. #loc "; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new BadExceptionDeclaredVisitor(this, inspectionManager, onTheFly); + } + + private class BadExceptionDeclaredVisitor extends BaseInspectionVisitor { + private BadExceptionDeclaredVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + final PsiReferenceList throwsList = method.getThrowsList(); + if(throwsList ==null) + { + return; + } + final PsiJavaCodeReferenceElement[] references = + throwsList.getReferenceElements(); + if(references == null) + { + return; + } + for (int i = 0; i < references.length; i++) { + final PsiClass thrownClass = (PsiClass) references[i].resolve(); + if(thrownClass != null) + { + final String text = thrownClass.getQualifiedName(); + for (Iterator iterator = exceptionsList.iterator(); iterator.hasNext();) { + final String exceptionClass = (String) iterator.next(); + if (text.equals(exceptionClass)) { + registerError(references[i]); + continue; + } + } + } + + } + } + } + + public class Form { + private JPanel contentPanel; + private JButton addButton; + private JButton deleteButton; + private JTable table; + + public Form() { + super(); + table.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); + table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + table.setRowSelectionAllowed(true); + table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + table.setEnabled(true); + final ReturnCheckSpecificationTableModel model = + new ReturnCheckSpecificationTableModel(); + table.setModel(model); + addButton.setEnabled(true); + addButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + exceptionsList.add(""); + model.fireTableStructureChanged(); + } + }); + deleteButton.setEnabled(true); + deleteButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + final int[] selectedRows = table.getSelectedRows(); + Arrays.sort(selectedRows); + for (int i = selectedRows.length - 1; i >= 0; i--) { + exceptionsList.remove(selectedRows[i]); + } + model.fireTableStructureChanged(); + } + }); + } + + public JComponent getContentPanel() { + return contentPanel; + } + } + + private class ReturnCheckSpecificationTableModel extends AbstractTableModel { + + public int getRowCount() { + return exceptionsList.size(); + } + + public int getColumnCount() { + return 1; + } + + public String getColumnName(int columnIndex) { + return "Exception class"; + } + + public Class getColumnClass(int columnIndex) { + return String.class; + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return true; + } + + public Object getValueAt(int rowIndex, int columnIndex) { + return exceptionsList.get(rowIndex); + } + + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + exceptionsList.set(rowIndex, aValue); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionThrown.form b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionThrown.form new file mode 100644 index 000000000000..d2f4bf33b5f1 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionThrown.form @@ -0,0 +1,46 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionThrownInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionThrownInspection.java new file mode 100644 index 000000000000..d9f90cb288e1 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/errorhandling/BadExceptionThrownInspection.java @@ -0,0 +1,198 @@ +package com.siyeh.ig.errorhandling; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.WriteExternalException; +import com.intellij.psi.*; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; +import org.jdom.Element; + +import javax.swing.*; +import javax.swing.border.EtchedBorder; +import javax.swing.table.AbstractTableModel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +public class BadExceptionThrownInspection extends ExpressionInspection { + public String exceptionCheckString = "java.lang.Throwable," + + "java.lang.Exception," + + "java.lang.Error," + + "java.lang.RuntimeException," + + "java.lang.NullPointerException," + + "java.lang.ClassCastException," + + "java.lang.ArrayOutOfBoundsException"; + + private List exceptionsList = new ArrayList(32); + + { + parseCallCheckString(); + } + + public void readSettings(Element element) throws InvalidDataException { + super.readSettings(element); + parseCallCheckString(); + } + + private void parseCallCheckString() { + exceptionsList.clear(); + final String[] strings = exceptionCheckString.split(","); + for (int i = 0; i < strings.length; i++ ) { + exceptionsList.add(strings[i]); + } + } + + public void writeSettings(Element element) throws WriteExternalException { + formatCallCheckString(); + super.writeSettings(element); + } + + private void formatCallCheckString() { + final StringBuffer buffer = new StringBuffer(); + boolean first = true; + for (Iterator iterator = exceptionsList.iterator(); iterator.hasNext();) { + if (first) { + first = false; + } else { + buffer.append(','); + } + final String exceptionName = (String) iterator.next(); + buffer.append(exceptionName); + } + exceptionCheckString = buffer.toString(); + } + + public String getDisplayName() { + return "Prohibitted exception thrown"; + } + + public String getGroupDisplayName() { + return GroupNames.ERRORHANDLING_GROUP_NAME; + } + + public JComponent createOptionsPanel() { + final Form form = new Form(); + return form.getContentPanel(); + } + + public String buildErrorString(PsiElement location) { + final PsiThrowStatement throwStatement = (PsiThrowStatement) location.getParent(); + final PsiExpression exception = throwStatement.getException(); + final PsiType type = exception.getType(); + final String exceptionName = type.getPresentableText(); + return "Prohibitted exception '" + exceptionName + "' thrown. #loc "; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new BadExceptionThrownVisitor(this, inspectionManager, onTheFly); + } + + private class BadExceptionThrownVisitor extends BaseInspectionVisitor { + private BadExceptionThrownVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitThrowStatement(PsiThrowStatement statement) { + super.visitThrowStatement(statement); + final PsiExpression exception = statement.getException(); + if(exception == null) + { + return; + } + final PsiType type = exception.getType(); + if(type == null) + { + return; + } + final String text = type.getCanonicalText(); + for (Iterator iterator = exceptionsList.iterator(); iterator.hasNext();) { + final String exceptionClass = (String) iterator.next(); + if(text.equals(exceptionClass)) + { + registerStatementError(statement); + return; + } + } + } + + } + + public class Form { + private JPanel contentPanel; + private JButton addButton; + private JButton deleteButton; + private JTable table; + + public Form() { + super(); + table.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); + table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + table.setRowSelectionAllowed(true); + table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); + table.setEnabled(true); + final ReturnCheckSpecificationTableModel model = + new ReturnCheckSpecificationTableModel(); + table.setModel(model); + addButton.setEnabled(true); + addButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + exceptionsList.add(""); + model.fireTableStructureChanged(); + } + }); + deleteButton.setEnabled(true); + deleteButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + final int[] selectedRows = table.getSelectedRows(); + Arrays.sort(selectedRows); + for (int i = selectedRows.length - 1; i >= 0; i--) { + exceptionsList.remove(selectedRows[i]); + } + model.fireTableStructureChanged(); + } + }); + } + + public JComponent getContentPanel() { + return contentPanel; + } + } + + private class ReturnCheckSpecificationTableModel extends AbstractTableModel { + + public int getRowCount() { + return exceptionsList.size(); + } + + public int getColumnCount() { + return 1; + } + + public String getColumnName(int columnIndex) { + return "Exception class"; + } + + public Class getColumnClass(int columnIndex) { + return String.class; + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return true; + } + + public Object getValueAt(int rowIndex, int columnIndex) { + return exceptionsList.get(rowIndex); + } + + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + exceptionsList.set(rowIndex, aValue); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/InlineVariableFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/InlineVariableFix.java new file mode 100644 index 000000000000..0e81e8f985e3 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/InlineVariableFix.java @@ -0,0 +1,25 @@ +package com.siyeh.ig.fixes; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiLocalVariable; +import com.intellij.refactoring.RefactoringActionHandler; +import com.intellij.refactoring.RefactoringActionHandlerFactory; +import com.siyeh.ig.InspectionGadgetsFix; + +public class InlineVariableFix extends InspectionGadgetsFix { + + public String getName() { + return "Inline variable"; + } + + public void applyFix(Project project, ProblemDescriptor problemDescriptor) { + final PsiElement nameElement = problemDescriptor.getPsiElement(); + final PsiLocalVariable variable = (PsiLocalVariable) nameElement.getParent(); + final RefactoringActionHandlerFactory factory = + RefactoringActionHandlerFactory.getInstance(); + final RefactoringActionHandler inlineHandler = factory.createInlineHandler(); + inlineHandler.invoke(project, new PsiElement[]{variable}, null); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/SimpleDateFormatWithoutLocaleInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/SimpleDateFormatWithoutLocaleInspection.java new file mode 100644 index 000000000000..2d75b07bad0f --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/internationalization/SimpleDateFormatWithoutLocaleInspection.java @@ -0,0 +1,61 @@ +package com.siyeh.ig.internationalization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.TypeUtils; + +public class SimpleDateFormatWithoutLocaleInspection extends ExpressionInspection { + + public String getDisplayName() { + return "Instantiating a SimpleDateFormat without a Locale"; + } + + public String getGroupDisplayName() { + return GroupNames.INTERNATIONALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Instantiating a #ref without specifying a Locale in an internationalized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SimpleDateFormatWithoutLocaleVisitor(this, inspectionManager, onTheFly); + } + + private static class SimpleDateFormatWithoutLocaleVisitor extends BaseInspectionVisitor { + private SimpleDateFormatWithoutLocaleVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + if(!TypeUtils.expressionHasType("java.util.SimpleDateFormat", expression)) + { + return; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + if(argumentList == null) + { + return; + } + final PsiExpression[] args = argumentList.getExpressions(); + if(args == null) + { + return; + } + for (int i = 0; i < args.length; i++) { + if(TypeUtils.expressionHasType("java.util.Locale", args[i])) + { + return; + } + } + final PsiJavaCodeReferenceElement classReference = expression.getClassReference(); + registerError(classReference); + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/MisorderedAssertEqualsParametersInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/MisorderedAssertEqualsParametersInspection.java new file mode 100644 index 000000000000..f284c546e5c9 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/MisorderedAssertEqualsParametersInspection.java @@ -0,0 +1,152 @@ +package com.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; + +public class MisorderedAssertEqualsParametersInspection extends ExpressionInspection { + private FlipParametersFix fix = new FlipParametersFix(); + + + public String getDisplayName() { + return "Misordered assertEquals parameters"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Parameters to #ref() in wrong order #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class FlipParametersFix extends InspectionGadgetsFix { + public String getName() { + return "Flip compared parameters"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement methodNameIdentifier = descriptor.getPsiElement(); + final PsiMethodCallExpression callExpression = (PsiMethodCallExpression) methodNameIdentifier.getParent().getParent(); + final PsiReferenceExpression methodExpression = callExpression.getMethodExpression(); + + final PsiMethod method = (PsiMethod) methodExpression.resolve(); + final PsiParameterList paramList = method.getParameterList(); + final PsiParameter[] parameters = paramList.getParameters(); + final PsiManager psiManager = callExpression.getManager(); + final GlobalSearchScope scope = GlobalSearchScope.allScope(project); + final PsiType stringType = PsiType.getJavaLangString(psiManager, scope); + final PsiType paramType1 = parameters[0].getType(); + final int expectedPosition; + final int actualPosition; + if (paramType1.equals(stringType) && parameters.length > 2) { + expectedPosition = 1; + actualPosition = 2; + } else { + expectedPosition = 0; + actualPosition = 1; + } + final PsiExpressionList argumentList = callExpression.getArgumentList(); + + final PsiExpression[] args = argumentList.getExpressions(); + final PsiExpression expectedArg = args[expectedPosition]; + final PsiExpression actualArg = args[actualPosition]; + final String actualArgText = actualArg.getText(); + final String expectedArgText = expectedArg.getText(); + replaceExpression(project, expectedArg, actualArgText); + replaceExpression(project, actualArg, expectedArgText); + } + + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MisorderedAssertEqualsParametersVisitor(this, inspectionManager, onTheFly); + } + + private static class MisorderedAssertEqualsParametersVisitor extends BaseInspectionVisitor { + + private MisorderedAssertEqualsParametersVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (!isAssertEquals(expression)) { + return; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + + final PsiMethod method = (PsiMethod) methodExpression.resolve(); + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + + final PsiManager psiManager = expression.getManager(); + + final Project project = psiManager.getProject(); + final GlobalSearchScope scope = GlobalSearchScope.allScope(project); + final PsiType stringType = PsiType.getJavaLangString(psiManager, scope); + final PsiType paramType1 = parameters[0].getType(); + final int expectedPosition; + final int actualPosition ; + if (paramType1.equals(stringType)&& parameters.length > 2) { + expectedPosition = 1; + actualPosition = 2; + } else { + expectedPosition = 0; + actualPosition = 1; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + if(argumentList == null) + { + return; + } + final PsiExpression[] args = argumentList.getExpressions(); + final PsiExpression expectedArg = args[expectedPosition]; + final PsiExpression actualArg = args[actualPosition]; + if(expectedArg == null || actualArg == null) + { + return; + } + if(expectedArg instanceof PsiLiteralExpression) + { + return; + } + if (!(actualArg instanceof PsiLiteralExpression)) + { + return; + } + registerMethodCallError(expression); + } + + private static boolean isAssertEquals(PsiMethodCallExpression expression) { + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if (!"assertEquals".equals(methodName)) { + return false; + } + final PsiMethod method = (PsiMethod) methodExpression.resolve(); + if (method == null) { + return false; + } + + final PsiClass targetClass = method.getContainingClass(); + if (!ClassUtils.isSubclass(targetClass, "junit.framework.Assert")) { + return false; + } + return true; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/SimplifiableJUnitAssertionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/SimplifiableJUnitAssertionInspection.java new file mode 100644 index 000000000000..1a2c91c05ee8 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/SimplifiableJUnitAssertionInspection.java @@ -0,0 +1,245 @@ +package com.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.ClassUtils; + +public class SimplifiableJUnitAssertionInspection extends ExpressionInspection { + private SimplifyJUnitAssertFix fix = new SimplifyJUnitAssertFix(); + + + public String getDisplayName() { + return "Simplifiable JUnit assertion"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref() can be simplified to assertEquals() #loc"; + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class SimplifyJUnitAssertFix extends InspectionGadgetsFix { + public String getName() { + return "Simplify assertion"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement methodNameIdentifier = descriptor.getPsiElement(); + final PsiMethodCallExpression callExpression = (PsiMethodCallExpression) methodNameIdentifier.getParent().getParent(); + final PsiReferenceExpression methodExpression = callExpression.getMethodExpression(); + + final PsiMethod method = (PsiMethod) methodExpression.resolve(); + final PsiParameterList paramList = method.getParameterList(); + final PsiParameter[] parameters = paramList.getParameters(); + + final PsiManager psiManager = callExpression.getManager(); + + final GlobalSearchScope scope = GlobalSearchScope.allScope(project); + final PsiType stringType = PsiType.getJavaLangString(psiManager, scope); + final PsiType paramType1 = parameters[0].getType(); + final PsiExpressionList argumentList = callExpression.getArgumentList(); + + final PsiExpression[] args = argumentList.getExpressions(); + final int testPosition; + final PsiExpression message; + if (paramType1.equals(stringType) && parameters.length > 2) { + testPosition = 1; + message = args[0]; + } else { + testPosition = 0; + message = null; + } + final PsiExpression testArg = args[testPosition]; + + PsiExpression lhs = null; + PsiExpression rhs = null; + if (testArg instanceof PsiBinaryExpression) { + lhs = ((PsiBinaryExpression) testArg).getLOperand(); + rhs = ((PsiBinaryExpression) testArg).getROperand(); + } else if (testArg instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression call = (PsiMethodCallExpression) testArg; + final PsiReferenceExpression equalityMethodExpression = call.getMethodExpression(); + final PsiExpressionList equalityArgumentList = call.getArgumentList(); + final PsiExpression[] equalityArgs = equalityArgumentList.getExpressions(); + rhs = equalityArgs[0]; + lhs = equalityMethodExpression.getQualifierExpression(); + } + if(!(lhs instanceof PsiLiteralExpression) && + rhs instanceof PsiLiteralExpression) + { + final PsiExpression temp = lhs; + lhs = rhs; + rhs = temp; + } + final StringBuffer newExpression = new StringBuffer("assertEquals("); + if(message!=null) + { + newExpression.append(message.getText()); + newExpression.append(','); + } + newExpression.append(lhs.getText()); + newExpression.append(','); + newExpression.append(rhs.getText()); + if(isFloatingPoint(lhs) || isFloatingPoint(rhs)) + { + newExpression.append(",0.0"); + } + newExpression.append(')'); + replaceExpression(project, callExpression, newExpression.toString()); + } + + private boolean isFloatingPoint(PsiExpression expression) { + final PsiType type = expression.getType(); + return PsiType.FLOAT.equals(type)|| PsiType.DOUBLE.equals(type); + } + + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new MisorderedAssertEqualsParametersVisitor(this, inspectionManager, onTheFly); + } + + private static class MisorderedAssertEqualsParametersVisitor extends BaseInspectionVisitor { + + private MisorderedAssertEqualsParametersVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (!isAssertTrue(expression)) { + return; + } + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + + final PsiMethod method = (PsiMethod) methodExpression.resolve(); + final PsiParameterList paramList = method.getParameterList(); + if (paramList == null) { + return; + } + final PsiParameter[] parameters = paramList.getParameters(); + + final PsiManager psiManager = expression.getManager(); + + final Project project = psiManager.getProject(); + final GlobalSearchScope scope = GlobalSearchScope.allScope(project); + final PsiType stringType = PsiType.getJavaLangString(psiManager, scope); + final PsiType paramType1 = parameters[0].getType(); + final int testPosition; + if (paramType1.equals(stringType) && parameters.length > 1) { + testPosition = 1; + } else { + testPosition = 0; + } + final PsiExpressionList argumentList = expression.getArgumentList(); + if (argumentList == null) { + return; + } + final PsiExpression[] args = argumentList.getExpressions(); + final PsiExpression testArg = args[testPosition]; + if (testArg == null) { + return; + } + if (!isEqualityComparison(testArg)) { + return; + } + registerMethodCallError(expression); + } + + private boolean isEqualityComparison(PsiExpression testArg) { + if (testArg instanceof PsiBinaryExpression) { + final PsiJavaToken sign = ((PsiBinaryExpression) testArg).getOperationSign(); + if(sign == null) + { + return false; + } + if(!sign.getTokenType().equals(JavaTokenType.EQEQ)) + { + return false; + } + final PsiExpression lhs = ((PsiBinaryExpression) testArg).getLOperand(); + if(lhs == null) + { + return false; + } + final PsiExpression rhs = ((PsiBinaryExpression) testArg).getROperand(); + if(rhs == null) + { + return false; + } + final PsiType type = lhs.getType(); + if(type == null) + { + return false; + } + if(!ClassUtils.isPrimitive(type)) + { + return false; + } + return true; + } else if (testArg instanceof PsiMethodCallExpression) { + final PsiMethodCallExpression call = (PsiMethodCallExpression) testArg; + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if(!"equals".equals(methodName)) + { + return false; + } + final PsiExpressionList argumentList = call.getArgumentList(); + if(argumentList == null) + { + return false; + } + final PsiExpression[] args = argumentList.getExpressions(); + if(args == null) + { + return false; + } + if(args.length!=1) + { + return false; + } + if(args[0] == null) + { + return false; + } + if(methodExpression.getQualifierExpression() == null) + { + return false; + } + return true; + } + return false; + } + + private static boolean isAssertTrue(PsiMethodCallExpression expression) { + final PsiReferenceExpression methodExpression = expression.getMethodExpression(); + final String methodName = methodExpression.getReferenceName(); + if (!"assertTrue".equals(methodName)) { + return false; + } + final PsiMethod method = (PsiMethod) methodExpression.resolve(); + if (method == null) { + return false; + } + + final PsiClass targetClass = method.getContainingClass(); + if (!ClassUtils.isSubclass(targetClass, "junit.framework.Assert")) { + return false; + } + return true; + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestCaseInProductCodeInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestCaseInProductCodeInspection.java new file mode 100644 index 000000000000..8c361e227e54 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/TestCaseInProductCodeInspection.java @@ -0,0 +1,54 @@ +package com.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.TestUtils; +import com.siyeh.ig.fixes.MoveClassFix; +import com.siyeh.ig.*; + +public class TestCaseInProductCodeInspection extends ClassInspection { + private final MoveClassFix fix = new MoveClassFix(); + + public String getDisplayName() { + return "JUnit TestCase in product source"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Test case #ref should probably be placed in a test source tree #loc"; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new TestCaseInProductCodeVisitor(this, inspectionManager, onTheFly); + } + + private static class TestCaseInProductCodeVisitor extends BaseInspectionVisitor { + + private TestCaseInProductCodeVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (!ClassUtils.isSubclass(aClass, "junit.framework.TestCase")) { + return; + } + if(TestUtils.isTest(aClass)) + { + return; + } + registerClassError(aClass); + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/junit/UnconstructableTestCaseInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/UnconstructableTestCaseInspection.java new file mode 100644 index 000000000000..f76a540d9554 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/junit/UnconstructableTestCaseInspection.java @@ -0,0 +1,84 @@ +package com.siyeh.ig.junit; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ClassInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.ClassUtils; + +public class UnconstructableTestCaseInspection extends ClassInspection { + + public String getDisplayName() { + return "Unconstructable JUnit TestCase"; + } + + public String getGroupDisplayName() { + return GroupNames.JUNIT_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Test case #ref is unusable by most test runners #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnconstructableTestCaseVisitor(this, inspectionManager, onTheFly); + } + + private static class UnconstructableTestCaseVisitor extends BaseInspectionVisitor { + + private UnconstructableTestCaseVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + if (aClass.isInterface() || aClass.isEnum() || aClass.isAnnotationType() || + aClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + return; + } + if (!ClassUtils.isSubclass(aClass, "junit.framework.TestCase")) { + return; + } + boolean hasConstructor = false; + boolean hasNoArgConstructor = false; + boolean hasStringConstructor = false; + + final PsiMethod[] constructors = aClass.getConstructors(); + if (constructors == null) { + return; + } + + for (int i = 0; i < constructors.length; i++) { + final PsiMethod constructor = constructors[i]; + hasConstructor = true; + if (!constructor.hasModifierProperty(PsiModifier.PUBLIC)) { + continue; + } + final PsiParameterList parameterList = constructor.getParameterList(); + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters.length == 0) { + hasNoArgConstructor = true; + } + if (parameters.length == 1) { + final PsiType type = parameters[0].getType(); + if (type != null) { + if (type.getCanonicalText().equals("java.lang.String")) { + hasStringConstructor = true; + } + } + } + } + + if (!hasConstructor) { + return; + } + if (hasNoArgConstructor || hasStringConstructor) { + return; + } + registerClassError(aClass); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ParameterNameDiffersFromOverriddenParameterInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ParameterNameDiffersFromOverriddenParameterInspection.java new file mode 100644 index 000000000000..98788b17f9da --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/naming/ParameterNameDiffersFromOverriddenParameterInspection.java @@ -0,0 +1,125 @@ +package com.siyeh.ig.naming; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiParameter; +import com.intellij.psi.PsiParameterList; +import com.intellij.psi.util.PsiSuperMethodUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.fixes.RenameFix; + +public class ParameterNameDiffersFromOverriddenParameterInspection extends MethodInspection { + + public String getDisplayName() { + return "Parameter name differs from parameter in overridden method"; + } + + public String getGroupDisplayName() { + return GroupNames.NAMING_CONVENTIONS_GROUP_NAME; + } + + protected InspectionGadgetsFix buildFix(PsiElement location) { + final PsiParameter parameter = (PsiParameter) location.getParent(); + final String parameterName = parameter.getName(); + final PsiMethod method = (PsiMethod) PsiTreeUtil.getParentOfType(parameter, PsiMethod.class); + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method); + final int index = method.getParameterList().getParameterIndex(parameter); + String name = ""; + for (int i = 0; i < superMethods.length; i++) { + final PsiMethod superMethod = superMethods[i]; + final PsiParameterList parameterList = superMethod.getParameterList(); + if (parameterList != null) { + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters != null) { + final String superParameterName = parameters[index].getName(); + if (superParameterName != null && !superParameterName.equals(parameterName)) { + name = superParameterName; + break; + } + } + } + } + return new RenameFix(name); + } + + protected boolean buildQuickFixesOnlyForOnTheFlyErrors() { + return true; + } + + public String buildErrorString(PsiElement location) { + final PsiParameter parameter = (PsiParameter) location.getParent(); + final String parameterName = parameter.getName(); + final PsiMethod method = (PsiMethod) PsiTreeUtil.getParentOfType(parameter, PsiMethod.class); + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method); + final int index = method.getParameterList().getParameterIndex(parameter); + String name = ""; + for (int i = 0; i < superMethods.length; i++) { + final PsiMethod superMethod = superMethods[i]; + final PsiParameterList parameterList = superMethod.getParameterList(); + if (parameterList != null) { + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters != null) { + final String superParameterName = parameters[index].getName(); + if (superParameterName != null && !superParameterName.equals(parameterName)) { + name = superParameterName; + break; + } + } + } + } + return "Parameter name '#ref' is different from parameter '" + name + "'overridden #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new ParameterNameDiffersFromOverriddenParameterVisitor(this, inspectionManager, onTheFly); + } + + private static class ParameterNameDiffersFromOverriddenParameterVisitor extends BaseInspectionVisitor { + private ParameterNameDiffersFromOverriddenParameterVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethod(PsiMethod method) { + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList == null) { + return; + } + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters == null || parameters.length == 0) { + return; + } + final PsiMethod[] superMethods = PsiSuperMethodUtil.findSuperMethods(method); + if (superMethods == null || superMethods.length == 0) { + return; + } + for (int i = 0; i < parameters.length; i++) { + checkParameter(parameters[i], i, superMethods); + } + } + + private void checkParameter(PsiParameter parameter, int index, PsiMethod[] superMethods) { + final String parameterName = parameter.getName(); + if(parameterName == null) + { + return; + } + for (int i = 0; i < superMethods.length; i++) { + final PsiMethod superMethod = superMethods[i]; + final PsiParameterList parameterList = superMethod.getParameterList(); + if (parameterList != null) { + final PsiParameter[] parameters = parameterList.getParameters(); + if (parameters != null) { + final String superParameterName = parameters[index].getName(); + if (superParameterName!=null &&!superParameterName.equals(parameterName)) { + registerVariableError(parameter); + } + } + } + } + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferFieldInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferFieldInspection.java new file mode 100644 index 000000000000..2748a3846848 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/StringBufferFieldInspection.java @@ -0,0 +1,56 @@ +package com.siyeh.ig.performance; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; +import com.intellij.psi.PsiType; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.FieldInspection; +import com.siyeh.ig.GroupNames; + +public class StringBufferFieldInspection extends FieldInspection { + + public String getDisplayName() { + return "StringBuffer field"; + } + + public String getGroupDisplayName() { + return GroupNames.PERFORMANCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiField field = (PsiField) location.getParent(); + final PsiType type = field.getType(); + final String typeName = type.getPresentableText(); + return typeName+ " field '#ref' #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new StringBufferFieldVisitor(this, inspectionManager, onTheFly); + } + + private static class StringBufferFieldVisitor extends BaseInspectionVisitor { + private StringBufferFieldVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitField(PsiField field) { + super.visitField(field); + final PsiType type = field.getType(); + if(type == null) + { + return; + } + final String text = type.getCanonicalText(); + if (!"java.lang.StringBuffer".equals(text) && + !"java.lang.StringBuilder".equals(text)) { + return; + } + registerFieldError(field); + + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/TestUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/TestUtils.java new file mode 100644 index 000000000000..5e35162705c7 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/TestUtils.java @@ -0,0 +1,46 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.roots.ProjectFileIndex; + +public class TestUtils { + private TestUtils() { + super(); + } + + public static boolean isTest(PsiClass aClass) { + final PsiManager manager = aClass.getManager(); + final PsiFile file = (PsiFile) PsiTreeUtil.getParentOfType(aClass, + PsiFile.class); + final VirtualFile virtualFile = file.getVirtualFile(); + final Project project = manager.getProject(); + return TestUtils.isTest(project, virtualFile); + } + + public static boolean isTest(PsiDirectory directory) { + final PsiManager manager = directory.getManager(); + final VirtualFile virtualFile = directory.getVirtualFile(); + final Project project = manager.getProject(); + return TestUtils.isTest(project, virtualFile); + } + + public static boolean isTest(Project project, VirtualFile virtualFile) { + if (virtualFile == null) { + return false; + } + final ProjectRootManager rootManager = ProjectRootManager.getInstance(project); + final ProjectFileIndex fileIndex = rootManager.getFileIndex(); + return fileIndex.isInTestSourceContent(virtualFile); + } + + public static boolean isTest(PsiJavaFile file) { + final PsiManager manager = file.getManager(); + final VirtualFile virtualFile = file.getVirtualFile(); + final Project project = manager.getProject(); + return TestUtils.isTest(project, virtualFile); + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableUsedVisitor.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableUsedVisitor.java new file mode 100644 index 000000000000..ec762cd402ec --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/VariableUsedVisitor.java @@ -0,0 +1,35 @@ +package com.siyeh.ig.psiutils; + +import com.intellij.psi.*; + +public class VariableUsedVisitor extends PsiRecursiveElementVisitor { + private boolean used = false; + private final PsiVariable variable; + + public VariableUsedVisitor(PsiVariable variable) { + super(); + this.variable = variable; + } + + public void visitReferenceExpression(PsiReferenceExpression ref) { + final PsiExpression qualifier = ref.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = ref.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + final PsiElement referent = ref.resolve(); + if (referent == null) { + return; + } + if (referent.equals(variable)) { + used = true; + } + } + + public boolean isUsed() { + return used; + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/resources/IOResourceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/resources/IOResourceInspection.java new file mode 100644 index 000000000000..769666126ea8 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/resources/IOResourceInspection.java @@ -0,0 +1,232 @@ +package com.siyeh.ig.resources; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.TypeUtils; + +public class IOResourceInspection extends ExpressionInspection { + + public String getDisplayName() { + return "I/O resource opened but not safely closed"; + } + + public String getGroupDisplayName() { + return GroupNames.RESOURCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiExpression expression = (PsiExpression) location; + final PsiType type = expression.getType(); + final String text = type.getPresentableText(); + return text + " should be opened in a try block, and closed in a finally block #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new IOResourceVisitor(this, inspectionManager, onTheFly); + } + + private static class IOResourceVisitor extends BaseInspectionVisitor { + private IOResourceVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + if (!isIOResource(expression)) { + return; + } + final PsiElement parent = expression.getParent(); + if(parent instanceof PsiExpressionList) + { + final PsiElement grandParent = parent.getParent(); + if(grandParent instanceof PsiNewExpression && + isIOResource((PsiNewExpression) grandParent)) + { + return; + } + } + if (!(parent instanceof PsiAssignmentExpression)) { + registerError(expression); + return; + } + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) parent; + final PsiExpression lhs = assignment.getLExpression(); + if(!(lhs instanceof PsiReferenceExpression)) + { + return; + } + final PsiElement referent = ((PsiReferenceExpression) lhs).resolve(); + if(referent == null || !(referent instanceof PsiVariable)) + { + return; + } + final PsiVariable boundVariable = (PsiVariable) referent; + final PsiElement containingBlock = PsiTreeUtil.getParentOfType(expression, PsiCodeBlock.class); + + if(isArgToResourceCreation(boundVariable, containingBlock)) + { + return; + } + PsiElement currentContext = expression; + while (true) { + final PsiTryStatement tryStatement = + (PsiTryStatement) PsiTreeUtil.getParentOfType(currentContext, PsiTryStatement.class); + if (tryStatement == null) { + registerError(expression); + return; + } + if (resourceIsOpenedInTryAndClosedInFinally(tryStatement, expression, boundVariable)) { + return; + } + currentContext = tryStatement; + } + + } + + private boolean isArgToResourceCreation(PsiVariable boundVariable, PsiElement scope) { + final UsedAsIOResourceArgVisitor visitor = new UsedAsIOResourceArgVisitor(boundVariable); + scope.accept(visitor); + return visitor.usedAsArgToResourceCreation(); + } + + private static boolean resourceIsOpenedInTryAndClosedInFinally(PsiTryStatement tryStatement, + PsiExpression lhs, PsiVariable boundVariable) { + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if (finallyBlock == null) { + return false; + } + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + if (tryBlock == null) { + return false; + } + if (!PsiTreeUtil.isAncestor(tryBlock, lhs, true)) { + return false; + } + return containsResourceClose(finallyBlock, boundVariable); + } + + private static boolean containsResourceClose(PsiCodeBlock finallyBlock, PsiVariable boundVariable) { + final StreamCloseVisitor visitor = new StreamCloseVisitor(boundVariable); + finallyBlock.accept(visitor); + return visitor.containsStreamClose(); + } + + } + + private static class StreamCloseVisitor extends PsiRecursiveElementVisitor { + private boolean containsStreamClose = false; + private PsiVariable streamToClose; + + private StreamCloseVisitor(PsiVariable streamToClose) { + super(); + this.streamToClose = streamToClose; + } + + public void visitReferenceExpression(PsiReferenceExpression ref) { + final PsiExpression qualifier = ref.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = ref.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + } + + public void visitMethodCallExpression(PsiMethodCallExpression call) { + super.visitMethodCallExpression(call); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"close".equals(methodName)) { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + if(!(qualifier instanceof PsiReferenceExpression)) + { + return; + } + final PsiElement referent = ((PsiReferenceExpression) qualifier).resolve(); + if (referent.equals(streamToClose)) { + containsStreamClose = true; + } + } + + public boolean containsStreamClose() { + return containsStreamClose; + } + } + + private static class UsedAsIOResourceArgVisitor extends PsiRecursiveElementVisitor { + private boolean usedAsArgToResourceCreation = false; + private PsiVariable ioResource; + + private UsedAsIOResourceArgVisitor(PsiVariable streamToClose) { + super(); + this.ioResource = streamToClose; + } + + public void visitReferenceExpression(PsiReferenceExpression ref) { + final PsiExpression qualifier = ref.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = ref.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + } + + public void visitNewExpression(PsiNewExpression expression) { + super.visitNewExpression(expression); + if(!isIOResource(expression)) + { + return; + } + final PsiExpressionList argList = expression.getArgumentList(); + if(argList == null) + { + return; + } + final PsiExpression[] expressions = argList.getExpressions(); + if(expressions == null || expressions.length == 0) + { + return; + } + final PsiExpression arg = expressions[0]; + if(arg == null || !(arg instanceof PsiReferenceExpression)) + { + return; + } + final PsiElement referent = ((PsiReferenceExpression) arg).resolve(); + if(referent ==null || !referent.equals(ioResource)) + { + return; + } + usedAsArgToResourceCreation = true; + } + + public boolean usedAsArgToResourceCreation() { + return usedAsArgToResourceCreation; + } + } + + private static boolean isIOResource(PsiNewExpression expression) { + return TypeUtils.expressionHasTypeOrSubtype("java.io.InputStream", expression) || + TypeUtils.expressionHasTypeOrSubtype("java.io.Writer", expression) || + TypeUtils.expressionHasTypeOrSubtype("java.io.Reader", expression) || + TypeUtils.expressionHasTypeOrSubtype("java.io.RandomAccessFile", expression) || + TypeUtils.expressionHasTypeOrSubtype("java.io.OutputStream", expression); + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/resources/JDBCResourceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/resources/JDBCResourceInspection.java new file mode 100644 index 000000000000..c2eced37f273 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/resources/JDBCResourceInspection.java @@ -0,0 +1,186 @@ +package com.siyeh.ig.resources; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ExpressionInspection; +import com.siyeh.ig.GroupNames; + +public class JDBCResourceInspection extends ExpressionInspection { + private static String[] creationMethodClassName = + new String[]{ + "java.sql.Driver", + "java.sql.DriverManager", + "java.sql.Connection", + "java.sql.Connection", + "java.sql.Connection", + "java.sql.Statement", + "java.sql.Statement", + }; + private static String[] creationMethodName = + new String[]{ + "connect", + "getConnection", + "createStatement", + "prepareStatement", + "prepareCall", + "executeQuery", + "getResultSet", + }; + + public String getDisplayName() { + return "JDBC resource opened but not safely closed"; + } + + public String getGroupDisplayName() { + return GroupNames.RESOURCE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + final PsiExpression expression = (PsiExpression) location; + final PsiType type = expression.getType(); + final String text = type.getPresentableText(); + return "JDBC " + text + " should be opened in a try block, and closed in a finally block #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new JDBCResourceVisitor(this, inspectionManager, onTheFly); + } + + private static class JDBCResourceVisitor extends BaseInspectionVisitor { + private JDBCResourceVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (!isJDBCResourceCreation(expression)) { + return; + } + final PsiElement parent = expression.getParent(); + if (!(parent instanceof PsiAssignmentExpression)) { + registerError(expression); + return; + } + final PsiAssignmentExpression assignment = (PsiAssignmentExpression) parent; + final PsiExpression lhs = assignment.getLExpression(); + if (!(lhs instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReferenceExpression) lhs).resolve(); + if (referent == null || !(referent instanceof PsiVariable)) { + return; + } + final PsiVariable boundVariable = (PsiVariable) referent; + + PsiElement currentContext = expression; + while (true) { + final PsiTryStatement tryStatement = + (PsiTryStatement) PsiTreeUtil.getParentOfType(currentContext, PsiTryStatement.class); + if (tryStatement == null) { + registerError(expression); + return; + } + if (resourceIsOpenedInTryAndClosedInFinally(tryStatement, expression, boundVariable)) { + return; + } + currentContext = tryStatement; + } + } + + + private static boolean resourceIsOpenedInTryAndClosedInFinally(PsiTryStatement tryStatement, + PsiExpression lhs, PsiVariable boundVariable) { + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if (finallyBlock == null) { + return false; + } + final PsiCodeBlock tryBlock = tryStatement.getTryBlock(); + if (tryBlock == null) { + return false; + } + if (!PsiTreeUtil.isAncestor(tryBlock, lhs, true)) { + return false; + } + return containsResourceClose(finallyBlock, boundVariable); + } + + private static boolean containsResourceClose(PsiCodeBlock finallyBlock, PsiVariable boundVariable) { + final ResourceCloseVisitor visitor = new ResourceCloseVisitor(boundVariable); + finallyBlock.accept(visitor); + return visitor.containsResourceClose(); + } + + } + + private static class ResourceCloseVisitor extends PsiRecursiveElementVisitor { + private boolean containsResourceClose = false; + private PsiVariable streamToClose; + + private ResourceCloseVisitor(PsiVariable streamToClose) { + super(); + this.streamToClose = streamToClose; + } + + public void visitReferenceExpression(PsiReferenceExpression ref) { + final PsiExpression qualifier = ref.getQualifierExpression(); + if (qualifier != null) { + qualifier.accept(this); + } + final PsiReferenceParameterList typeParameters = ref.getParameterList(); + if (typeParameters != null) { + typeParameters.accept(this); + } + } + + public void visitMethodCallExpression(PsiMethodCallExpression call) { + super.visitMethodCallExpression(call); + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + if (methodExpression == null) { + return; + } + final String methodName = methodExpression.getReferenceName(); + if (!"close".equals(methodName)) { + return; + } + final PsiExpression qualifier = methodExpression.getQualifierExpression(); + if (qualifier == null) { + return; + } + if (!(qualifier instanceof PsiReferenceExpression)) { + return; + } + final PsiElement referent = ((PsiReferenceExpression) qualifier).resolve(); + if (referent.equals(streamToClose)) { + containsResourceClose = true; + } + } + + public boolean containsResourceClose() { + return containsResourceClose; + } + } + + private static boolean isJDBCResourceCreation(PsiMethodCallExpression expression) { + final PsiMethod method = expression.resolveMethod(); + if (method == null) { + return false; + } + final PsiClass containingClass = method.getContainingClass(); + final String name = method.getName(); + if (containingClass == null) { + return false; + } + final String className = containingClass.getQualifiedName(); + for (int i = 0; i < creationMethodName.length; i++) { + if (name.equals(creationMethodName[i]) && + className.equals(creationMethodClassName[i])) { + return true; + } + } + return false; + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerialPersistentFieldsWithWrongSignatureInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerialPersistentFieldsWithWrongSignatureInspection.java new file mode 100644 index 000000000000..4a759a087def --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/serialization/SerialPersistentFieldsWithWrongSignatureInspection.java @@ -0,0 +1,71 @@ +package com.siyeh.ig.serialization; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.ClassInspection; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.psiutils.SerializationUtils; + +public class SerialPersistentFieldsWithWrongSignatureInspection extends ClassInspection { + + public String getDisplayName() { + return "'serialPersistentFields' field not declared 'private static final ObjectStreamField[]'"; + } + + public String getGroupDisplayName() { + return GroupNames.SERIALIZATION_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "#ref field of a Serializable class is not declared 'private static final ObjectStreamField[]' #loc "; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new SerializableDefinesSerialVersionUIDVisitor(this, inspectionManager, onTheFly); + } + + private static class SerializableDefinesSerialVersionUIDVisitor extends BaseInspectionVisitor { + private SerializableDefinesSerialVersionUIDVisitor(BaseInspection inspection, + InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + // no call to super, so it doesn't drill down + if (aClass.isInterface() || aClass.isAnnotationType()) { + return; + } + if (!SerializationUtils.isSerializable(aClass)) { + return; + } + final PsiField[] fields = aClass.getFields(); + for (int i = 0; i < fields.length; i++) { + final PsiField field = fields[i]; + if (isSerialPersistentFields(field)) { + if (!field.hasModifierProperty(PsiModifier.PRIVATE) || + !field.hasModifierProperty(PsiModifier.STATIC) || + !field.hasModifierProperty(PsiModifier.FINAL)) { + registerFieldError(field); + } else { + final PsiType type = field.getType(); + if (type != null) { + final String text = type.getCanonicalText(); + if (!text.equals("java.io.ObjectStreamField[]")) { + registerFieldError(field); + } + } + } + } + } + } + + private static boolean isSerialPersistentFields(PsiField field) { + final String fieldName = field.getName(); + return "serialPersistentFields".equals(fieldName); + } + + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/threading/CallToNativeMethodWhileLockedInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/CallToNativeMethodWhileLockedInspection.java new file mode 100644 index 000000000000..4817dfeb168e --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/threading/CallToNativeMethodWhileLockedInspection.java @@ -0,0 +1,82 @@ +package com.siyeh.ig.threading; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.GroupNames; +import com.siyeh.ig.StatementInspection; + +public class CallToNativeMethodWhileLockedInspection extends StatementInspection { + + public String getDisplayName() { + return "Call to a native method while locked"; + } + + public String getGroupDisplayName() { + return GroupNames.THREADING_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Call to native method #ref() in a synchronized context #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new WaitNotInSynchronizedContextVisitor(this, inspectionManager, onTheFly); + } + + private static class WaitNotInSynchronizedContextVisitor extends BaseInspectionVisitor { + private boolean m_inSynchronizedContext = false; + + private WaitNotInSynchronizedContextVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + if (!m_inSynchronizedContext) { + return; + } + final PsiMethod method = expression.resolveMethod(); + if(method == null) + { + return; + } + if (!method.hasModifierProperty(PsiModifier.NATIVE)) { + return; + } + final PsiClass containingClass = method.getContainingClass(); + if(containingClass == null) + { + return; + } + final String className = containingClass.getQualifiedName(); + if("java.lang.Object".equals(className)) + { + return; + } + registerMethodCallError(expression); + } + + public void visitMethod(PsiMethod method) { + final boolean wasInSynchronizedContext = m_inSynchronizedContext; + if (method.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + + m_inSynchronizedContext = true; + } + super.visitMethod(method); + if (method.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + + m_inSynchronizedContext = wasInSynchronizedContext; + } + } + + public void visitSynchronizedStatement(PsiSynchronizedStatement psiSynchronizedStatement) { + final boolean wasInSynchronizedContext = m_inSynchronizedContext; + m_inSynchronizedContext = true; + super.visitSynchronizedStatement(psiSynchronizedStatement); + m_inSynchronizedContext = wasInSynchronizedContext; + } + } + +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryConstructorInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryConstructorInspection.java new file mode 100644 index 000000000000..e9bd5b51c5e6 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryConstructorInspection.java @@ -0,0 +1,90 @@ +package com.siyeh.ig.verbose; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.siyeh.ig.*; + +public class UnnecessaryConstructorInspection extends ClassInspection { + private final UnnecessaryConstructorFix fix = new UnnecessaryConstructorFix(); + + public String getDisplayName() { + return "Redundant no-arg constructor"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "No-arg constructor #ref is unnecessary #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryConstructorVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return fix; + } + + private static class UnnecessaryConstructorFix extends InspectionGadgetsFix { + public String getName() { + return "Remove redundant constructor"; + } + + public void applyFix(Project project, ProblemDescriptor descriptor) { + final PsiElement nameIdentifier = descriptor.getPsiElement(); + final PsiElement constructor = nameIdentifier.getParent(); + deleteElement(constructor); + } + + } + + private static class UnnecessaryConstructorVisitor extends BaseInspectionVisitor { + private UnnecessaryConstructorVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitClass(PsiClass aClass) { + + final PsiMethod[] constructors = aClass.getConstructors(); + if (constructors == null) { + return; + } + if (constructors.length != 1) { + return; + } + final PsiMethod constructor = constructors[0]; + if (!constructor.hasModifierProperty(PsiModifier.PUBLIC)) { + return; + } + final PsiParameterList parameterList = constructor.getParameterList(); + if (parameterList == null) { + return; + } + if (parameterList.getParameters().length != 0) { + return; + } + final PsiCodeBlock body = constructor.getBody(); + if (body == null) { + return; + } + final PsiStatement[] statements = body.getStatements(); + if (statements == null) { + return; + } + if (statements.length == 0) { + registerMethodError(constructor); + }else if(statements.length == 1) + { + final PsiStatement statement = statements[0]; + if("super();".equals(statement.getText())) + { + registerMethodError(constructor); + } + } + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryLocalVariableInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryLocalVariableInspection.java new file mode 100644 index 000000000000..44e749d0ae26 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/verbose/UnnecessaryLocalVariableInspection.java @@ -0,0 +1,267 @@ +package com.siyeh.ig.verbose; + +import com.intellij.codeInspection.InspectionManager; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.*; +import com.siyeh.ig.psiutils.*; +import com.siyeh.ig.fixes.InlineVariableFix; + +public class UnnecessaryLocalVariableInspection extends StatementInspection { + + public String getDisplayName() { + return "Redundant local variable"; + } + + public String getGroupDisplayName() { + return GroupNames.VERBOSE_GROUP_NAME; + } + + public String buildErrorString(PsiElement location) { + return "Local variable #ref is redundant #loc"; + } + + public BaseInspectionVisitor createVisitor(InspectionManager inspectionManager, boolean onTheFly) { + return new UnnecessaryLocalVariableVisitor(this, inspectionManager, onTheFly); + } + + public InspectionGadgetsFix buildFix(PsiElement location) { + return new InlineVariableFix(); + } + + private static class UnnecessaryLocalVariableVisitor extends BaseInspectionVisitor { + private UnnecessaryLocalVariableVisitor(BaseInspection inspection, InspectionManager inspectionManager, boolean isOnTheFly) { + super(inspection, inspectionManager, isOnTheFly); + } + + public void visitLocalVariable(PsiLocalVariable variable) { + super.visitLocalVariable(variable); + if (isCopyVariable(variable)) { + registerVariableError(variable); + } else if (isImmediatelyReturned(variable)) { + registerVariableError(variable); + } else if (isImmediatelyAssigned(variable)) { + registerVariableError(variable); + }else if (isImmediatelyAssignedAsDeclaration(variable)) { + registerVariableError(variable); + } + } + } + + private static boolean isCopyVariable(PsiVariable variable) { + final PsiExpression initializer = variable.getInitializer(); + if (initializer == null) { + return false; + } + if (!(initializer instanceof PsiReferenceExpression)) { + return false; + } + final PsiElement referent = ((PsiReference) initializer).resolve(); + if (referent == null) { + return false; + } + if (!(referent instanceof PsiLocalVariable || referent instanceof PsiParameter)) { + return false; + } + final PsiCodeBlock containingScope = + (PsiCodeBlock) PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (containingScope == null) { + return false; + } + final VariableAssignedVisitor visitor = new VariableAssignedVisitor(variable); + containingScope.accept(visitor); + if (visitor.isAssigned()) { + return false; + } + + final PsiVariable initialization = (PsiVariable) referent; + final VariableAssignedVisitor visitor2 = new VariableAssignedVisitor(variable); + containingScope.accept(visitor2); + if (visitor2.isAssigned()) { + return false; + } + if (!initialization.hasModifierProperty(PsiModifier.FINAL) + && variable.hasModifierProperty(PsiModifier.FINAL)) { + if (variableIsUsedInInnerClass(containingScope, variable)) { + return false; + } + } + return true; + } + + private static boolean isImmediatelyReturned(PsiVariable variable) { + + final PsiCodeBlock containingScope = + (PsiCodeBlock) PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (containingScope == null) { + return false; + } + final PsiDeclarationStatement declarationStatement = + (PsiDeclarationStatement) PsiTreeUtil.getParentOfType(variable, PsiDeclarationStatement.class); + if (declarationStatement == null) { + return false; + } + PsiStatement nextStatement = null; + final PsiStatement[] statements = containingScope.getStatements(); + for (int i = 0; i < statements.length - 1; i++) { + if (statements[i].equals(declarationStatement)) { + nextStatement = statements[i + 1]; + } + } + if (nextStatement == null) { + return false; + } + if (!(nextStatement instanceof PsiReturnStatement)) { + return false; + } + final PsiReturnStatement returnStatement = (PsiReturnStatement) nextStatement; + final PsiExpression returnValue = returnStatement.getReturnValue(); + if (returnValue == null) { + return false; + } + if (!(returnValue instanceof PsiReferenceExpression)) { + return false; + } + final PsiElement referent = ((PsiReferenceExpression) returnValue).resolve(); + if (referent == null || !referent.equals(variable)) { + return false; + } + return true; + } + + private static boolean isImmediatelyAssigned(PsiVariable variable) { + + final PsiCodeBlock containingScope = + (PsiCodeBlock) PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (containingScope == null) { + return false; + } + final PsiDeclarationStatement declarationStatement = + (PsiDeclarationStatement) PsiTreeUtil.getParentOfType(variable, PsiDeclarationStatement.class); + if (declarationStatement == null) { + return false; + } + + PsiStatement nextStatement = null; + int followingStatementNumber = 0; + final PsiStatement[] statements = containingScope.getStatements(); + for (int i = 0; i < statements.length - 1; i++) { + if (statements[i].equals(declarationStatement)) { + nextStatement = statements[i + 1]; + followingStatementNumber = i + 2; + } + } + if (nextStatement == null) { + return false; + } + if (!(nextStatement instanceof PsiExpressionStatement)) { + return false; + } + final PsiExpressionStatement expressionStatement = (PsiExpressionStatement) nextStatement; + final PsiExpression expression = expressionStatement.getExpression(); + if (expression == null) { + return false; + } + if (!(expression instanceof PsiAssignmentExpression)) { + return false; + } + final PsiExpression rhs = ((PsiAssignmentExpression) expression).getRExpression(); + if (rhs == null) { + return false; + } + if (!(rhs instanceof PsiReferenceExpression)) { + return false; + } + final PsiElement referent = ((PsiReferenceExpression) rhs).resolve(); + if (referent == null || !referent.equals(variable)) { + return false; + } + for (int i = followingStatementNumber; i < statements.length; i++) { + if (variableIsUsedInStatement(statements[i], variable)) { + return false; + } + + } + return true; + } + + + private static boolean isImmediatelyAssignedAsDeclaration(PsiVariable variable) { + + final PsiCodeBlock containingScope = + (PsiCodeBlock) PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + if (containingScope == null) { + return false; + } + final PsiDeclarationStatement declarationStatement = + (PsiDeclarationStatement) PsiTreeUtil.getParentOfType(variable, PsiDeclarationStatement.class); + if (declarationStatement == null) { + return false; + } + + PsiStatement nextStatement = null; + int followingStatementNumber = 0; + final PsiStatement[] statements = containingScope.getStatements(); + for (int i = 0; i < statements.length - 1; i++) { + if (statements[i].equals(declarationStatement)) { + nextStatement = statements[i + 1]; + followingStatementNumber = i + 2; + } + } + if (nextStatement == null) { + return false; + } + if (!(nextStatement instanceof PsiDeclarationStatement)) { + return false; + } + final PsiDeclarationStatement declaration = (PsiDeclarationStatement) nextStatement; + final PsiElement[] declarations = declaration.getDeclaredElements(); + if (declarations == null) { + return false; + } + if (declarations.length != 1) { + return false; + } + if (!(declarations[0] instanceof PsiVariable)) { + return false; + } + + final PsiExpression rhs = ((PsiVariable) declarations[0]).getInitializer(); + if (rhs == null) { + return false; + } + if (!(rhs instanceof PsiReferenceExpression)) { + return false; + } + final PsiElement referent = ((PsiReferenceExpression) rhs).resolve(); + if (referent == null || !referent.equals(variable)) { + return false; + } + for (int i = followingStatementNumber; i < statements.length; i++) { + if (variableIsUsedInStatement(statements[i], variable)) { + return false; + } + + } + return true; + } + + private static boolean variableIsUsedInInnerClass(PsiCodeBlock block, + PsiVariable variable) { + + final VariableUsedInInnerClassVisitor visitor + = new VariableUsedInInnerClassVisitor(variable); + block.accept(visitor); + return visitor.isUsedInInnerClass(); + } + + private static boolean variableIsUsedInStatement(PsiStatement statement, + PsiVariable variable) { + + final VariableUsedVisitor visitor + = new VariableUsedVisitor(variable); + statement.accept(visitor); + return visitor.isUsed(); + } + +} diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/BadExceptionCaught.html b/plugins/InspectionGadgets/src/inspectionDescriptions/BadExceptionCaught.html new file mode 100644 index 000000000000..2cae3deb7ca6 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/BadExceptionCaught.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports any instances of catch clauses +which catch inappropriate exceptions. Some exceptions, for instance +java.lang.NullPointerException and +java.lang.IllegalMonitorStateException represent programming errors +and so should almost certainly not be caught in production code. +

+Use the list below to specify which exceptions should be flagged by this inspection. +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/BadExceptionDeclared.html b/plugins/InspectionGadgets/src/inspectionDescriptions/BadExceptionDeclared.html new file mode 100644 index 000000000000..03cd3e41ca26 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/BadExceptionDeclared.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any instances of throws clauses on +methods which throw inappropriate exceptions. One use of this inspection would be to warn of +throws clauses which throw overly generic exceptions +(e.g. java.lang.Exception) or +

+Use the list below to specify which exceptions should be flagged by this inspection. +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/BadExceptionThrown.html b/plugins/InspectionGadgets/src/inspectionDescriptions/BadExceptionThrown.html new file mode 100644 index 000000000000..7925dd4867b8 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/BadExceptionThrown.html @@ -0,0 +1,12 @@ + +
+ +This inspection reports any instances of throw statements +which throw inappropriate exceptions. One use of this inspection would be to warn of +throw statements which throw overly generic exceptions +(e.g. java.lang.Exception or +java.io.IOException). +

+Use the list below to specify which exceptions should be flagged by this inspection. +

Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CallToNativeMethodWhileLocked.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CallToNativeMethodWhileLocked.html new file mode 100644 index 000000000000..de328b3f412b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CallToNativeMethodWhileLocked.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any to methods declared native while in +a synchronized block or method. While not necessarily representing a problem, such calls cause +an expensive context switch, and are best kept out of synchronized contexts, if possible. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/IOResource.html b/plugins/InspectionGadgets/src/inspectionDescriptions/IOResource.html new file mode 100644 index 000000000000..89aee1d1895b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/IOResource.html @@ -0,0 +1,15 @@ + + +
+ +This inspection reports any I/O resource which is not opened in a try +block and closed in the corresponding finally block. Such resources may +be inadvertantly leaked if an exception is thrown before the resouce is closed. I/O resources reported +by this inspection include any instances of java.io.InputStream, + java.io.OutputStream, + java.io.Reader, + java.io.Writer and + java.io.RandomAccessFile . I/O resources which are wrapped by other I/O resources +are not reported, as the wrapped resource will be closed by the wrapping resource. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofChain.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofChain.html new file mode 100644 index 000000000000..ef7c159a25cb --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InstanceofChain.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any chains of if-else statements all of whose conditions are instanceof expressions +(or combinations of such expressions). Such constructions usually indicate a failure of object-oriented design, which +dictates that such type-based dispatch should be done via polymorphic method calls rather than explicit chains +of type tests. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/JDBCResource.html b/plugins/InspectionGadgets/src/inspectionDescriptions/JDBCResource.html new file mode 100644 index 000000000000..a2c40828145d --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/JDBCResource.html @@ -0,0 +1,13 @@ + +
+ +This inspection reports any JDBC resource which is not opened in a try +block and closed in the corresponding finally block. Such resources may +be inadvertantly leaked if an exception is thrown before the resouce is closed. JDBC resources reported +by this inspection include any instances of java.sql.Connection, + java.sql.Statement, + java.sql.PreparedStatement, + java.sql.CallableStatement, +and java.sql.ResultSet. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MisorderedAssertEqualsParameters.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MisorderedAssertEqualsParameters.html new file mode 100644 index 000000000000..607fc83778e6 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MisorderedAssertEqualsParameters.html @@ -0,0 +1,8 @@ + +
+This inspection reports any calls to JUnit assertEquals() which have +a non-literal as the expected result argument and a literal as the actual result argument. Such calls +will behave fine for assertions which pass, but may give confusing error reports if their expected and actual +arguments differ. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ParameterNameDiffersFromOverriddenParameter.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ParameterNameDiffersFromOverriddenParameter.html new file mode 100644 index 000000000000..a0be21b5502f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ParameterNameDiffersFromOverriddenParameter.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of parameters which have different names from corresponding +parameters in methods they override. While legal in Java, such inconsistent names may be confusing, +and lessen the documentation benefits of good naming practices. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SerialPersistentFieldsWithWrongSignature.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SerialPersistentFieldsWithWrongSignature.html new file mode 100644 index 000000000000..bceb5aab0fb1 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SerialPersistentFieldsWithWrongSignature.html @@ -0,0 +1,7 @@ + +
+ +This inspection reports any instances of Serializable classes whose serialPersistentFields field. +is not declared private static final ObjectStreamField. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SimpleDateFormatWithoutLocale.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SimpleDateFormatWithoutLocale.html new file mode 100644 index 000000000000..415499825e25 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SimpleDateFormatWithoutLocale.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instantiations of java.util.SimpleDateFormat +which do not specify a java.util.Locale. +Such calls are usually incorrect in an internationalized environment. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SimplifiableJUnitAssertion.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SimplifiableJUnitAssertion.html new file mode 100644 index 000000000000..07749c1844dc --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SimplifiableJUnitAssertion.html @@ -0,0 +1,7 @@ + +
+This inspection reports any JUnit assertTrue calls +which can be replaced by equivalent assertEquals calls. assertEquals +calls will normally give better error messages in case of test failure than assertTrue can. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StaticCallOnSubclass.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticCallOnSubclass.html new file mode 100644 index 000000000000..bbd1488d3da2 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StaticCallOnSubclass.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of static method calls where the call is qualified +by a subclass of the declaring class, rather than the declaring class itself +(e.g. MyThreadSubclass.sleep()). Java allows such qualification, but such calls +may be confusing, and may indicate a subtle confusion of inheritance and overriding. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferField.html new file mode 100644 index 000000000000..9f7cabddb87b --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringBufferField.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of fields with type +java.lang.StringBuffer or java.lang.StringBuilder. +StringBuffer fields can grow without limit, and are often the cause of +memory leaks. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/TestCaseInProductCode.html b/plugins/InspectionGadgets/src/inspectionDescriptions/TestCaseInProductCode.html new file mode 100644 index 000000000000..52c38e6729e2 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/TestCaseInProductCode.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of JUnit test cases in product source trees. +This most likely indicates programmer error, and can result in test code being shipped +into production. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnconstructableTestCase.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnconstructableTestCase.html new file mode 100644 index 000000000000..4ec9c2ea7ac2 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnconstructableTestCase.html @@ -0,0 +1,9 @@ + +
+ +This inspection reports any instances of non-abstract JUnit test cases which do not +expose a public no-arg constructor or a public constructor which takes a single string +as an argument. Such test cases will be unrunnable by most JUnit test runners, including +IDEA's. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryConstructor.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryConstructor.html new file mode 100644 index 000000000000..0ff685749819 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryConstructor.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports any instances of unnecessary public no-arg constructors. +If such a constructor is the only constructor for a class and performs no initialization, +it can be safely removed. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryLocalVariable.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryLocalVariable.html new file mode 100644 index 000000000000..066d7ee5312f --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UnnecessaryLocalVariable.html @@ -0,0 +1,10 @@ + +
+ +This inspection reports any instances of unnecessary local variables, which add +nothing to the comprehensibility of a method. Variables caught include local variables +which are immediately returned, local variables that are immediately assigned to another +variable and then not used, and local variables which always have the same value as another +local variable or parameter. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/UseOfAnotherObjectsPrivateField.html b/plugins/InspectionGadgets/src/inspectionDescriptions/UseOfAnotherObjectsPrivateField.html new file mode 100644 index 000000000000..0218c5610bd0 --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/UseOfAnotherObjectsPrivateField.html @@ -0,0 +1,11 @@ + +
+ +This inspection reports any uses of another object's private or protected fields. Java +allows the use of such fields for objects of the same class as the current objects, but +some coding styles discourage this use. Additionally, such direct access to private fields +may fail in component-oriented architectures such (e.g. Spring, Hibernate) which expect all access +to other objects to be through method calls so as to allow the framework to mediate all access +using proxies. +
Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/FeatureEnvy.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/FeatureEnvy.java new file mode 100644 index 000000000000..65ead907f664 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/FeatureEnvy.java @@ -0,0 +1,31 @@ +package com.siyeh.igtest.abstraction; + +class TestFeatureEnvySuper { + void foo1() { + } + + void foo2() { + } + + void foo3() { + } +} + +class TestFeatureEnvySuper2 { + void test() { + TestFeatureEnvySuper test = new TestFeatureEnvySuper(); + test.foo1(); + test.foo2(); + test.foo3(); + } +} + +public class FeatureEnvy extends TestFeatureEnvySuper { + class Inner { + void test() { + foo1(); + foo2(); + foo3(); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/StaticCallOnSubclass.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/StaticCallOnSubclass.java new file mode 100644 index 000000000000..edee3629f52f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/StaticCallOnSubclass.java @@ -0,0 +1,14 @@ +package com.siyeh.igtest.bugs; + +public class StaticCallOnSubclass { + + public void foo() throws InterruptedException { + Thread.sleep(1000L); + InnerThread.sleep(1000L); + } + + class InnerThread extends Thread + { + + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/UseOfAnotherObjectsPrivateFieldInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/UseOfAnotherObjectsPrivateFieldInspection.java new file mode 100644 index 000000000000..fa2ef949c267 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/encapsulation/UseOfAnotherObjectsPrivateFieldInspection.java @@ -0,0 +1,16 @@ +package com.siyeh.igtest.encapsulation; + +public class UseOfAnotherObjectsPrivateFieldInspection { + public int foo; + protected int bar; + private int baz; + + public void fooBar(UseOfAnotherObjectsPrivateFieldInspection copy) + { + foo = copy.foo; + bar = copy.bar; + baz = copy.baz; + foo = this.baz; + foo = baz; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/UnconstructableTestCase1.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/UnconstructableTestCase1.java new file mode 100644 index 000000000000..de82bb98e5d2 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/UnconstructableTestCase1.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class UnconstructableTestCase1 extends TestCase +{ + private UnconstructableTestCase1() + { + System.out.println(""); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/UnconstructableTestCase2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/UnconstructableTestCase2.java new file mode 100644 index 000000000000..182534298c33 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/UnconstructableTestCase2.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class UnconstructableTestCase2 extends TestCase +{ + public UnconstructableTestCase2(Object foo) + { + System.out.println(""); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/UnconstructableTestCase3.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/UnconstructableTestCase3.java new file mode 100644 index 000000000000..dba593783e86 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/UnconstructableTestCase3.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class UnconstructableTestCase3 extends TestCase +{ + public UnconstructableTestCase3() + { + System.out.println(""); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/UnconstructableTestCase4.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/UnconstructableTestCase4.java new file mode 100644 index 000000000000..78456782767d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/junit/UnconstructableTestCase4.java @@ -0,0 +1,12 @@ +package com.siyeh.igtest.junit; + +import junit.framework.TestCase; + +public class UnconstructableTestCase4 extends TestCase +{ + public UnconstructableTestCase4(String foo) + { + System.out.println(""); + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/package2/Test.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/package2/Test.java new file mode 100644 index 000000000000..9fef1dd1e9c1 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/package2/Test.java @@ -0,0 +1,4 @@ +package com.siyeh.igtest.naming.package2; + +public class Test { +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/package2/Test2.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/package2/Test2.java new file mode 100644 index 000000000000..caf8fe6d5308 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/naming/package2/Test2.java @@ -0,0 +1,4 @@ +package com.siyeh.igtest.naming.package2; + +public class Test2 { +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/AutoUnboxingInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/AutoUnboxingInspection.java new file mode 100644 index 000000000000..ea7634e30c7a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/portability/AutoUnboxingInspection.java @@ -0,0 +1,15 @@ +package com.siyeh.igtest.portability; + +public class AutoUnboxingInspection { + public void foo() { + Integer bar = 3; + int baz = new Integer(3); + if (new Integer(3) == 3) { + return; + } + if (new Integer(3) + 3 == 3) { + return; + } + Integer x = 3; + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/resources/JDBCResourceInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/resources/JDBCResourceInspection.java new file mode 100644 index 000000000000..c00cf709e3d8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/resources/JDBCResourceInspection.java @@ -0,0 +1,144 @@ +package com.siyeh.igtest.resources; + +import java.sql.*; + +public class JDBCResourceInspection { + private Driver driver; + + public void foo() throws SQLException { + Connection connection = null; + try { + connection = driver.connect("foo", null); + } finally { + connection.close(); + } + + } + + public void foo2() throws SQLException { + Connection connection = null; + try { + connection = driver.connect("foo", null); + } finally { + } + } + + + public void foo3() throws SQLException { + Connection connection = null; + try { + connection = driver.connect("foo", null); + connection.createStatement(); + } finally { + connection.close(); + } + + } + + public void foo4() throws SQLException { + Connection connection = null; + Statement statement = null; + try { + connection = driver.connect("foo", null); + statement = connection.createStatement(); + } finally { + connection.close(); + } + + } + + public void foo5() throws SQLException { + Connection connection = null; + Statement statement = null; + try { + connection = driver.connect("foo", null); + statement = connection.createStatement(); + } finally { + statement.close(); + connection.close(); + } + + } + + public void foo6() throws SQLException { + Connection connection = null; + Statement statement = null; + try { + connection = driver.connect("foo", null); + statement = connection.prepareStatement("foo"); + } finally { + connection.close(); + } + + } + + public void foo7() throws SQLException { + Connection connection = null; + Statement statement = null; + try { + connection = driver.connect("foo", null); + statement = connection.prepareStatement("foo"); + } finally { + statement.close(); + connection.close(); + } + + } + + public void foo8() throws SQLException { + Connection connection = null; + Statement statement = null; + try { + connection = driver.connect("foo", null); + statement = connection.prepareCall("foo"); + } finally { + connection.close(); + } + + } + + public void foo9() throws SQLException { + Connection connection = null; + Statement statement = null; + try { + connection = driver.connect("foo", null); + statement = connection.prepareCall("foo"); + } finally { + statement.close(); + connection.close(); + } + + } + + public void foo10() throws SQLException { + Connection connection = null; + Statement statement = null; + ResultSet resultSet = null; + try { + connection = driver.connect("foo", null); + statement = connection.prepareCall("foo"); + resultSet = statement.executeQuery("foo"); + } finally { + statement.close(); + connection.close(); + } + + } + + public void foo11() throws SQLException { + Connection connection = null; + Statement statement = null; + ResultSet resultSet = null; + try { + connection = driver.connect("foo", null); + statement = connection.prepareCall("foo"); + resultSet = statement.executeQuery("foo"); + } finally { + resultSet.close(); + statement.close(); + connection.close(); + } + + } + +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryBlockStatementInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryBlockStatementInspection.java new file mode 100644 index 000000000000..4d4d0a19a353 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryBlockStatementInspection.java @@ -0,0 +1,9 @@ +package com.siyeh.igtest.verbose; + +public class UnnecessaryBlockStatementInspection { + public static void main(String[] args) { + { + System.out.println("3"); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryLocalVariableInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryLocalVariableInspection.java new file mode 100644 index 000000000000..99a25eaa4a37 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/verbose/UnnecessaryLocalVariableInspection.java @@ -0,0 +1,22 @@ +package com.siyeh.igtest.verbose; + +public class UnnecessaryLocalVariableInspection { + + public int foo() { + int a = 2; + int b = a; + return b; + } + + public int bar() { + int b = 3; + return b; + } + + public int baz() { + int a; + int b = 3; + a = b; + return a; + } +}